Reformat all the things. Have fun with merge conflicts.

This commit is contained in:
Pierre Bourdon
2016-06-24 10:43:46 +02:00
parent 2115e8a4a6
commit 3570c7f03a
1116 changed files with 187405 additions and 180344 deletions

View File

@ -2,86 +2,85 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D/BoundingBox.h"
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "VideoBackends/D3D/BoundingBox.h"
#include "VideoCommon/VideoConfig.h"
namespace DX11
{
static ID3D11Buffer* s_bbox_buffer;
static ID3D11Buffer* s_bbox_staging_buffer;
static ID3D11UnorderedAccessView* s_bbox_uav;
static ID3D11UnorderedAccessView* s_bbox_uav;
ID3D11UnorderedAccessView* &BBox::GetUAV()
ID3D11UnorderedAccessView*& BBox::GetUAV()
{
return s_bbox_uav;
return s_bbox_uav;
}
void BBox::Init()
{
if (g_ActiveConfig.backend_info.bSupportsBBox)
{
// Create 2 buffers here.
// First for unordered access on default pool.
auto desc = CD3D11_BUFFER_DESC(4 * sizeof(s32), D3D11_BIND_UNORDERED_ACCESS, D3D11_USAGE_DEFAULT, 0, 0, 4);
int initial_values[4] = { 0, 0, 0, 0 };
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = initial_values;
data.SysMemPitch = 4 * sizeof(s32);
data.SysMemSlicePitch = 0;
HRESULT hr;
hr = D3D::device->CreateBuffer(&desc, &data, &s_bbox_buffer);
CHECK(SUCCEEDED(hr), "Create BoundingBox Buffer.");
D3D::SetDebugObjectName(s_bbox_buffer, "BoundingBox Buffer");
if (g_ActiveConfig.backend_info.bSupportsBBox)
{
// Create 2 buffers here.
// First for unordered access on default pool.
auto desc = CD3D11_BUFFER_DESC(4 * sizeof(s32), D3D11_BIND_UNORDERED_ACCESS,
D3D11_USAGE_DEFAULT, 0, 0, 4);
int initial_values[4] = {0, 0, 0, 0};
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = initial_values;
data.SysMemPitch = 4 * sizeof(s32);
data.SysMemSlicePitch = 0;
HRESULT hr;
hr = D3D::device->CreateBuffer(&desc, &data, &s_bbox_buffer);
CHECK(SUCCEEDED(hr), "Create BoundingBox Buffer.");
D3D::SetDebugObjectName(s_bbox_buffer, "BoundingBox Buffer");
// Second to use as a staging buffer.
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.BindFlags = 0;
hr = D3D::device->CreateBuffer(&desc, nullptr, &s_bbox_staging_buffer);
CHECK(SUCCEEDED(hr), "Create BoundingBox Staging Buffer.");
D3D::SetDebugObjectName(s_bbox_staging_buffer, "BoundingBox Staging Buffer");
// Second to use as a staging buffer.
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.BindFlags = 0;
hr = D3D::device->CreateBuffer(&desc, nullptr, &s_bbox_staging_buffer);
CHECK(SUCCEEDED(hr), "Create BoundingBox Staging Buffer.");
D3D::SetDebugObjectName(s_bbox_staging_buffer, "BoundingBox Staging Buffer");
// UAV is required to allow concurrent access.
D3D11_UNORDERED_ACCESS_VIEW_DESC UAVdesc = {};
UAVdesc.Format = DXGI_FORMAT_R32_SINT;
UAVdesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
UAVdesc.Buffer.FirstElement = 0;
UAVdesc.Buffer.Flags = 0;
UAVdesc.Buffer.NumElements = 4;
hr = D3D::device->CreateUnorderedAccessView(s_bbox_buffer, &UAVdesc, &s_bbox_uav);
CHECK(SUCCEEDED(hr), "Create BoundingBox UAV.");
D3D::SetDebugObjectName(s_bbox_uav, "BoundingBox UAV");
}
// UAV is required to allow concurrent access.
D3D11_UNORDERED_ACCESS_VIEW_DESC UAVdesc = {};
UAVdesc.Format = DXGI_FORMAT_R32_SINT;
UAVdesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
UAVdesc.Buffer.FirstElement = 0;
UAVdesc.Buffer.Flags = 0;
UAVdesc.Buffer.NumElements = 4;
hr = D3D::device->CreateUnorderedAccessView(s_bbox_buffer, &UAVdesc, &s_bbox_uav);
CHECK(SUCCEEDED(hr), "Create BoundingBox UAV.");
D3D::SetDebugObjectName(s_bbox_uav, "BoundingBox UAV");
}
}
void BBox::Shutdown()
{
SAFE_RELEASE(s_bbox_buffer);
SAFE_RELEASE(s_bbox_staging_buffer);
SAFE_RELEASE(s_bbox_uav);
SAFE_RELEASE(s_bbox_buffer);
SAFE_RELEASE(s_bbox_staging_buffer);
SAFE_RELEASE(s_bbox_uav);
}
void BBox::Set(int index, int value)
{
D3D11_BOX box{ index * sizeof(s32), 0, 0, (index + 1) * sizeof(s32), 1, 1 };
D3D::context->UpdateSubresource(s_bbox_buffer, 0, &box, &value, 0, 0);
D3D11_BOX box{index * sizeof(s32), 0, 0, (index + 1) * sizeof(s32), 1, 1};
D3D::context->UpdateSubresource(s_bbox_buffer, 0, &box, &value, 0, 0);
}
int BBox::Get(int index)
{
int data = 0;
D3D::context->CopyResource(s_bbox_staging_buffer, s_bbox_buffer);
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr = D3D::context->Map(s_bbox_staging_buffer, 0, D3D11_MAP_READ, 0, &map);
if (SUCCEEDED(hr))
{
data = ((s32*)map.pData)[index];
}
D3D::context->Unmap(s_bbox_staging_buffer, 0);
return data;
int data = 0;
D3D::context->CopyResource(s_bbox_staging_buffer, s_bbox_buffer);
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr = D3D::context->Map(s_bbox_staging_buffer, 0, D3D11_MAP_READ, 0, &map);
if (SUCCEEDED(hr))
{
data = ((s32*)map.pData)[index];
}
D3D::context->Unmap(s_bbox_staging_buffer, 0);
return data;
}
};

View File

@ -7,16 +7,14 @@
namespace DX11
{
class BBox
{
public:
static ID3D11UnorderedAccessView* &GetUAV();
static void Init();
static void Shutdown();
static ID3D11UnorderedAccessView*& GetUAV();
static void Init();
static void Shutdown();
static void Set(int index, int value);
static int Get(int index);
static void Set(int index, int value);
static int Get(int index);
};
};

View File

@ -5,9 +5,9 @@
#include <algorithm>
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Common/Logging/Log.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DTexture.h"
@ -15,7 +15,6 @@
namespace DX11
{
HINSTANCE hD3DCompilerDll = nullptr;
D3DREFLECT PD3DReflect = nullptr;
pD3DCompile PD3DCompile = nullptr;
@ -25,7 +24,11 @@ CREATEDXGIFACTORY PCreateDXGIFactory = nullptr;
HINSTANCE hDXGIDll = nullptr;
int dxgi_dll_ref = 0;
typedef HRESULT (WINAPI* D3D11CREATEDEVICEANDSWAPCHAIN)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, CONST DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
typedef HRESULT(WINAPI* D3D11CREATEDEVICEANDSWAPCHAIN)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE,
UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT,
CONST DXGI_SWAP_CHAIN_DESC*,
IDXGISwapChain**, ID3D11Device**,
D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
static D3D11CREATEDEVICE PD3D11CreateDevice = nullptr;
D3D11CREATEDEVICEANDSWAPCHAIN PD3D11CreateDeviceAndSwapChain = nullptr;
HINSTANCE hD3DDll = nullptr;
@ -33,7 +36,6 @@ int d3d_dll_ref = 0;
namespace D3D
{
ID3D11Device* device = nullptr;
ID3D11DeviceContext* context = nullptr;
static IDXGISwapChain* swapchain = nullptr;
@ -42,16 +44,13 @@ D3D_FEATURE_LEVEL featlevel;
D3DTexture2D* backbuf = nullptr;
HWND hWnd;
std::vector<DXGI_SAMPLE_DESC> aa_modes; // supported AA modes of the current adapter
std::vector<DXGI_SAMPLE_DESC> aa_modes; // supported AA modes of the current adapter
bool bgra_textures_supported;
#define NUM_SUPPORTED_FEATURE_LEVELS 3
const D3D_FEATURE_LEVEL supported_feature_levels[NUM_SUPPORTED_FEATURE_LEVELS] = {
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0};
unsigned int xres, yres;
@ -59,500 +58,569 @@ bool bFrameInProgress = false;
HRESULT LoadDXGI()
{
if (dxgi_dll_ref++ > 0) return S_OK;
if (dxgi_dll_ref++ > 0)
return S_OK;
if (hDXGIDll) return S_OK;
hDXGIDll = LoadLibraryA("dxgi.dll");
if (!hDXGIDll)
{
MessageBoxA(nullptr, "Failed to load dxgi.dll", "Critical error", MB_OK | MB_ICONERROR);
--dxgi_dll_ref;
return E_FAIL;
}
PCreateDXGIFactory = (CREATEDXGIFACTORY)GetProcAddress(hDXGIDll, "CreateDXGIFactory");
if (PCreateDXGIFactory == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for CreateDXGIFactory!", "Critical error", MB_OK | MB_ICONERROR);
if (hDXGIDll)
return S_OK;
hDXGIDll = LoadLibraryA("dxgi.dll");
if (!hDXGIDll)
{
MessageBoxA(nullptr, "Failed to load dxgi.dll", "Critical error", MB_OK | MB_ICONERROR);
--dxgi_dll_ref;
return E_FAIL;
}
PCreateDXGIFactory = (CREATEDXGIFACTORY)GetProcAddress(hDXGIDll, "CreateDXGIFactory");
if (PCreateDXGIFactory == nullptr)
MessageBoxA(nullptr, "GetProcAddress failed for CreateDXGIFactory!", "Critical error",
MB_OK | MB_ICONERROR);
return S_OK;
return S_OK;
}
HRESULT LoadD3D()
{
if (d3d_dll_ref++ > 0) return S_OK;
if (d3d_dll_ref++ > 0)
return S_OK;
if (hD3DDll) return S_OK;
hD3DDll = LoadLibraryA("d3d11.dll");
if (!hD3DDll)
{
MessageBoxA(nullptr, "Failed to load d3d11.dll", "Critical error", MB_OK | MB_ICONERROR);
--d3d_dll_ref;
return E_FAIL;
}
PD3D11CreateDevice = (D3D11CREATEDEVICE)GetProcAddress(hD3DDll, "D3D11CreateDevice");
if (PD3D11CreateDevice == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDevice!", "Critical error", MB_OK | MB_ICONERROR);
if (hD3DDll)
return S_OK;
hD3DDll = LoadLibraryA("d3d11.dll");
if (!hD3DDll)
{
MessageBoxA(nullptr, "Failed to load d3d11.dll", "Critical error", MB_OK | MB_ICONERROR);
--d3d_dll_ref;
return E_FAIL;
}
PD3D11CreateDevice = (D3D11CREATEDEVICE)GetProcAddress(hD3DDll, "D3D11CreateDevice");
if (PD3D11CreateDevice == nullptr)
MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDevice!", "Critical error",
MB_OK | MB_ICONERROR);
PD3D11CreateDeviceAndSwapChain = (D3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(hD3DDll, "D3D11CreateDeviceAndSwapChain");
if (PD3D11CreateDeviceAndSwapChain == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDeviceAndSwapChain!", "Critical error", MB_OK | MB_ICONERROR);
PD3D11CreateDeviceAndSwapChain =
(D3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(hD3DDll, "D3D11CreateDeviceAndSwapChain");
if (PD3D11CreateDeviceAndSwapChain == nullptr)
MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDeviceAndSwapChain!",
"Critical error", MB_OK | MB_ICONERROR);
return S_OK;
return S_OK;
}
HRESULT LoadD3DCompiler()
{
if (d3dcompiler_dll_ref++ > 0) return S_OK;
if (hD3DCompilerDll) return S_OK;
if (d3dcompiler_dll_ref++ > 0)
return S_OK;
if (hD3DCompilerDll)
return S_OK;
// try to load D3DCompiler first to check whether we have proper runtime support
// try to use the dll the backend was compiled against first - don't bother about debug runtimes
hD3DCompilerDll = LoadLibraryA(D3DCOMPILER_DLL_A);
if (!hD3DCompilerDll)
{
// if that fails, use the dll which should be available in every SDK which officially supports DX11.
hD3DCompilerDll = LoadLibraryA("D3DCompiler_42.dll");
if (!hD3DCompilerDll)
{
MessageBoxA(nullptr, "Failed to load D3DCompiler_42.dll, update your DX11 runtime, please", "Critical error", MB_OK | MB_ICONERROR);
return E_FAIL;
}
else
{
NOTICE_LOG(VIDEO, "Successfully loaded D3DCompiler_42.dll. If you're having trouble, try updating your DX runtime first.");
}
}
// try to load D3DCompiler first to check whether we have proper runtime support
// try to use the dll the backend was compiled against first - don't bother about debug runtimes
hD3DCompilerDll = LoadLibraryA(D3DCOMPILER_DLL_A);
if (!hD3DCompilerDll)
{
// if that fails, use the dll which should be available in every SDK which officially supports
// DX11.
hD3DCompilerDll = LoadLibraryA("D3DCompiler_42.dll");
if (!hD3DCompilerDll)
{
MessageBoxA(nullptr, "Failed to load D3DCompiler_42.dll, update your DX11 runtime, please",
"Critical error", MB_OK | MB_ICONERROR);
return E_FAIL;
}
else
{
NOTICE_LOG(VIDEO, "Successfully loaded D3DCompiler_42.dll. If you're having trouble, try "
"updating your DX runtime first.");
}
}
PD3DReflect = (D3DREFLECT)GetProcAddress(hD3DCompilerDll, "D3DReflect");
if (PD3DReflect == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for D3DReflect!", "Critical error", MB_OK | MB_ICONERROR);
PD3DCompile = (pD3DCompile)GetProcAddress(hD3DCompilerDll, "D3DCompile");
if (PD3DCompile == nullptr) MessageBoxA(nullptr, "GetProcAddress failed for D3DCompile!", "Critical error", MB_OK | MB_ICONERROR);
PD3DReflect = (D3DREFLECT)GetProcAddress(hD3DCompilerDll, "D3DReflect");
if (PD3DReflect == nullptr)
MessageBoxA(nullptr, "GetProcAddress failed for D3DReflect!", "Critical error",
MB_OK | MB_ICONERROR);
PD3DCompile = (pD3DCompile)GetProcAddress(hD3DCompilerDll, "D3DCompile");
if (PD3DCompile == nullptr)
MessageBoxA(nullptr, "GetProcAddress failed for D3DCompile!", "Critical error",
MB_OK | MB_ICONERROR);
return S_OK;
return S_OK;
}
void UnloadDXGI()
{
if (!dxgi_dll_ref) return;
if (--dxgi_dll_ref != 0) return;
if (!dxgi_dll_ref)
return;
if (--dxgi_dll_ref != 0)
return;
if (hDXGIDll) FreeLibrary(hDXGIDll);
hDXGIDll = nullptr;
PCreateDXGIFactory = nullptr;
if (hDXGIDll)
FreeLibrary(hDXGIDll);
hDXGIDll = nullptr;
PCreateDXGIFactory = nullptr;
}
void UnloadD3D()
{
if (!d3d_dll_ref) return;
if (--d3d_dll_ref != 0) return;
if (!d3d_dll_ref)
return;
if (--d3d_dll_ref != 0)
return;
if (hD3DDll) FreeLibrary(hD3DDll);
hD3DDll = nullptr;
PD3D11CreateDevice = nullptr;
PD3D11CreateDeviceAndSwapChain = nullptr;
if (hD3DDll)
FreeLibrary(hD3DDll);
hD3DDll = nullptr;
PD3D11CreateDevice = nullptr;
PD3D11CreateDeviceAndSwapChain = nullptr;
}
void UnloadD3DCompiler()
{
if (!d3dcompiler_dll_ref) return;
if (--d3dcompiler_dll_ref != 0) return;
if (!d3dcompiler_dll_ref)
return;
if (--d3dcompiler_dll_ref != 0)
return;
if (hD3DCompilerDll) FreeLibrary(hD3DCompilerDll);
hD3DCompilerDll = nullptr;
PD3DReflect = nullptr;
if (hD3DCompilerDll)
FreeLibrary(hD3DCompilerDll);
hD3DCompilerDll = nullptr;
PD3DReflect = nullptr;
}
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter)
{
std::vector<DXGI_SAMPLE_DESC> _aa_modes;
std::vector<DXGI_SAMPLE_DESC> _aa_modes;
// NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND shader resources.
// Thus, we can't have MSAA with 10.0 level hardware.
ID3D11Device* _device;
ID3D11DeviceContext* _context;
D3D_FEATURE_LEVEL feat_level;
HRESULT hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &_device, &feat_level, &_context);
if (FAILED(hr) || feat_level == D3D_FEATURE_LEVEL_10_0)
{
DXGI_SAMPLE_DESC desc;
desc.Count = 1;
desc.Quality = 0;
_aa_modes.push_back(desc);
SAFE_RELEASE(_context);
SAFE_RELEASE(_device);
}
else
{
for (int samples = 0; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples)
{
UINT quality_levels = 0;
_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, &quality_levels);
// NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND
// shader resources.
// Thus, we can't have MSAA with 10.0 level hardware.
ID3D11Device* _device;
ID3D11DeviceContext* _context;
D3D_FEATURE_LEVEL feat_level;
HRESULT hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels,
NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &_device,
&feat_level, &_context);
if (FAILED(hr) || feat_level == D3D_FEATURE_LEVEL_10_0)
{
DXGI_SAMPLE_DESC desc;
desc.Count = 1;
desc.Quality = 0;
_aa_modes.push_back(desc);
SAFE_RELEASE(_context);
SAFE_RELEASE(_device);
}
else
{
for (int samples = 0; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples)
{
UINT quality_levels = 0;
_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, &quality_levels);
DXGI_SAMPLE_DESC desc;
desc.Count = samples;
desc.Quality = 0;
DXGI_SAMPLE_DESC desc;
desc.Count = samples;
desc.Quality = 0;
if (quality_levels > 0)
_aa_modes.push_back(desc);
}
_context->Release();
_device->Release();
}
return _aa_modes;
if (quality_levels > 0)
_aa_modes.push_back(desc);
}
_context->Release();
_device->Release();
}
return _aa_modes;
}
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter)
{
D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1;
PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, nullptr, &feat_level, nullptr);
return feat_level;
D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1;
PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED,
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION,
nullptr, &feat_level, nullptr);
return feat_level;
}
HRESULT Create(HWND wnd)
{
hWnd = wnd;
HRESULT hr;
hWnd = wnd;
HRESULT hr;
RECT client;
GetClientRect(hWnd, &client);
xres = client.right - client.left;
yres = client.bottom - client.top;
RECT client;
GetClientRect(hWnd, &client);
xres = client.right - client.left;
yres = client.bottom - client.top;
hr = LoadDXGI();
if (SUCCEEDED(hr)) hr = LoadD3D();
if (SUCCEEDED(hr)) hr = LoadD3DCompiler();
if (FAILED(hr))
{
UnloadDXGI();
UnloadD3D();
UnloadD3DCompiler();
return hr;
}
hr = LoadDXGI();
if (SUCCEEDED(hr))
hr = LoadD3D();
if (SUCCEEDED(hr))
hr = LoadD3DCompiler();
if (FAILED(hr))
{
UnloadDXGI();
UnloadD3D();
UnloadD3DCompiler();
return hr;
}
IDXGIFactory* factory;
IDXGIAdapter* adapter;
IDXGIOutput* output;
hr = PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
if (FAILED(hr)) MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
IDXGIFactory* factory;
IDXGIAdapter* adapter;
IDXGIOutput* output;
hr = PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
if (FAILED(hr))
MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"),
MB_OK | MB_ICONERROR);
hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter);
if (FAILED(hr))
{
// try using the first one
hr = factory->EnumAdapters(0, &adapter);
if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
}
hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter);
if (FAILED(hr))
{
// try using the first one
hr = factory->EnumAdapters(0, &adapter);
if (FAILED(hr))
MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 backend"),
MB_OK | MB_ICONERROR);
}
// TODO: Make this configurable
hr = adapter->EnumOutputs(0, &output);
if (FAILED(hr))
{
// try using the first one
IDXGIAdapter* firstadapter;
hr = factory->EnumAdapters(0, &firstadapter);
if (!FAILED(hr))
hr = firstadapter->EnumOutputs(0, &output);
if (FAILED(hr)) MessageBox(wnd,
_T("Failed to enumerate outputs!\n")
_T("This usually happens when you've set your video adapter to the Nvidia GPU in an Optimus-equipped system.\n")
_T("Set Dolphin to use the high-performance graphics in Nvidia's drivers instead and leave Dolphin's video adapter set to the Intel GPU."),
_T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
SAFE_RELEASE(firstadapter);
}
// TODO: Make this configurable
hr = adapter->EnumOutputs(0, &output);
if (FAILED(hr))
{
// try using the first one
IDXGIAdapter* firstadapter;
hr = factory->EnumAdapters(0, &firstadapter);
if (!FAILED(hr))
hr = firstadapter->EnumOutputs(0, &output);
if (FAILED(hr))
MessageBox(wnd, _T("Failed to enumerate outputs!\n")
_T("This usually happens when you've set your video adapter to the Nvidia ")
_T("GPU in an Optimus-equipped system.\n")
_T("Set Dolphin to use the high-performance graphics in Nvidia's drivers ")
_T("instead and leave Dolphin's video adapter set to the Intel GPU."),
_T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
SAFE_RELEASE(firstadapter);
}
// get supported AA modes
aa_modes = EnumAAModes(adapter);
// get supported AA modes
aa_modes = EnumAAModes(adapter);
if (std::find_if(
aa_modes.begin(),
aa_modes.end(),
[](const DXGI_SAMPLE_DESC& desc) {return desc.Count == g_Config.iMultisamples;}
) == aa_modes.end())
{
g_Config.iMultisamples = 1;
UpdateActiveConfig();
}
if (std::find_if(aa_modes.begin(), aa_modes.end(), [](const DXGI_SAMPLE_DESC& desc) {
return desc.Count == g_Config.iMultisamples;
}) == aa_modes.end())
{
g_Config.iMultisamples = 1;
UpdateActiveConfig();
}
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {};
swap_chain_desc.BufferCount = 1;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = wnd;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SampleDesc.Quality = 0;
swap_chain_desc.Windowed = !g_Config.bFullscreen;
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {};
swap_chain_desc.BufferCount = 1;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = wnd;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SampleDesc.Quality = 0;
swap_chain_desc.Windowed = !g_Config.bFullscreen;
DXGI_OUTPUT_DESC out_desc = {};
output->GetDesc(&out_desc);
DXGI_OUTPUT_DESC out_desc = {};
output->GetDesc(&out_desc);
DXGI_MODE_DESC mode_desc = {};
mode_desc.Width = out_desc.DesktopCoordinates.right - out_desc.DesktopCoordinates.left;
mode_desc.Height = out_desc.DesktopCoordinates.bottom - out_desc.DesktopCoordinates.top;
mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, nullptr);
if (FAILED(hr)) MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
DXGI_MODE_DESC mode_desc = {};
mode_desc.Width = out_desc.DesktopCoordinates.right - out_desc.DesktopCoordinates.left;
mode_desc.Height = out_desc.DesktopCoordinates.bottom - out_desc.DesktopCoordinates.top;
mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, nullptr);
if (FAILED(hr))
MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 backend"),
MB_OK | MB_ICONERROR);
if (swap_chain_desc.Windowed)
{
// forcing buffer resolution to xres and yres..
// this is not a problem as long as we're in windowed mode
swap_chain_desc.BufferDesc.Width = xres;
swap_chain_desc.BufferDesc.Height = yres;
}
if (swap_chain_desc.Windowed)
{
// forcing buffer resolution to xres and yres..
// this is not a problem as long as we're in windowed mode
swap_chain_desc.BufferDesc.Width = xres;
swap_chain_desc.BufferDesc.Height = yres;
}
#if defined(_DEBUG) || defined(DEBUGFAST)
// Creating debug devices can sometimes fail if the user doesn't have the correct
// version of the DirectX SDK. If it does, simply fallback to a non-debug device.
{
hr = PD3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG,
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device,
&featlevel, &context);
// Debugbreak on D3D error
if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), (void**)&debug)))
{
ID3D11InfoQueue* infoQueue = nullptr;
if (SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&infoQueue)))
{
infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
// Creating debug devices can sometimes fail if the user doesn't have the correct
// version of the DirectX SDK. If it does, simply fallback to a non-debug device.
{
hr = PD3D11CreateDeviceAndSwapChain(
adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG, supported_feature_levels,
NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device,
&featlevel, &context);
// Debugbreak on D3D error
if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), (void**)&debug)))
{
ID3D11InfoQueue* infoQueue = nullptr;
if (SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&infoQueue)))
{
infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
D3D11_MESSAGE_ID hide[] =
{
D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS
};
D3D11_MESSAGE_ID hide[] = {D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS};
D3D11_INFO_QUEUE_FILTER filter = {};
filter.DenyList.NumIDs = sizeof(hide) / sizeof(D3D11_MESSAGE_ID);
filter.DenyList.pIDList = hide;
infoQueue->AddStorageFilterEntries(&filter);
infoQueue->Release();
}
}
}
D3D11_INFO_QUEUE_FILTER filter = {};
filter.DenyList.NumIDs = sizeof(hide) / sizeof(D3D11_MESSAGE_ID);
filter.DenyList.pIDList = hide;
infoQueue->AddStorageFilterEntries(&filter);
infoQueue->Release();
}
}
}
if (FAILED(hr))
if (FAILED(hr))
#endif
{
hr = PD3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
D3D11_CREATE_DEVICE_SINGLETHREADED,
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device,
&featlevel, &context);
}
{
hr = PD3D11CreateDeviceAndSwapChain(
adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED,
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &swap_chain_desc,
&swapchain, &device, &featlevel, &context);
}
if (FAILED(hr))
{
MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
SAFE_RELEASE(device);
SAFE_RELEASE(context);
SAFE_RELEASE(swapchain);
return E_FAIL;
}
if (FAILED(hr))
{
MessageBox(
wnd,
_T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"),
_T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
SAFE_RELEASE(device);
SAFE_RELEASE(context);
SAFE_RELEASE(swapchain);
return E_FAIL;
}
// prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER
// does not work so we disable all monitoring of window messages. However this
// may make it more difficult for DXGI to handle display mode changes.
hr = factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(hr)) MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
// prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER
// does not work so we disable all monitoring of window messages. However this
// may make it more difficult for DXGI to handle display mode changes.
hr = factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(hr))
MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"),
MB_OK | MB_ICONERROR);
SetDebugObjectName((ID3D11DeviceChild*)context, "device context");
SAFE_RELEASE(factory);
SAFE_RELEASE(output);
SAFE_RELEASE(adapter);
SetDebugObjectName((ID3D11DeviceChild*)context, "device context");
SAFE_RELEASE(factory);
SAFE_RELEASE(output);
SAFE_RELEASE(adapter);
ID3D11Texture2D* buf;
hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
if (FAILED(hr))
{
MessageBox(wnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
SAFE_RELEASE(device);
SAFE_RELEASE(context);
SAFE_RELEASE(swapchain);
return E_FAIL;
}
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
SAFE_RELEASE(buf);
CHECK(backbuf!=nullptr, "Create back buffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
ID3D11Texture2D* buf;
hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
if (FAILED(hr))
{
MessageBox(wnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"),
MB_OK | MB_ICONERROR);
SAFE_RELEASE(device);
SAFE_RELEASE(context);
SAFE_RELEASE(swapchain);
return E_FAIL;
}
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
SAFE_RELEASE(buf);
CHECK(backbuf != nullptr, "Create back buffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
context->OMSetRenderTargets(1, &backbuf->GetRTV(), nullptr);
context->OMSetRenderTargets(1, &backbuf->GetRTV(), nullptr);
// BGRA textures are easier to deal with in TextureCache, but might not be supported by the hardware
UINT format_support;
device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support);
bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
// BGRA textures are easier to deal with in TextureCache, but might not be supported by the
// hardware
UINT format_support;
device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support);
bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
stateman = new StateManager;
return S_OK;
stateman = new StateManager;
return S_OK;
}
void Close()
{
// we can't release the swapchain while in fullscreen.
swapchain->SetFullscreenState(false, nullptr);
// we can't release the swapchain while in fullscreen.
swapchain->SetFullscreenState(false, nullptr);
// release all bound resources
context->ClearState();
SAFE_RELEASE(backbuf);
SAFE_RELEASE(swapchain);
SAFE_DELETE(stateman);
context->Flush(); // immediately destroy device objects
// release all bound resources
context->ClearState();
SAFE_RELEASE(backbuf);
SAFE_RELEASE(swapchain);
SAFE_DELETE(stateman);
context->Flush(); // immediately destroy device objects
SAFE_RELEASE(context);
ULONG references = device->Release();
SAFE_RELEASE(context);
ULONG references = device->Release();
#if defined(_DEBUG) || defined(DEBUGFAST)
if (debug)
{
--references; // the debug interface increases the refcount of the device, subtract that.
if (references)
{
// print out alive objects, but only if we actually have pending references
// note this will also print out internal live objects to the debug console
debug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL);
}
SAFE_RELEASE(debug)
}
if (debug)
{
--references; // the debug interface increases the refcount of the device, subtract that.
if (references)
{
// print out alive objects, but only if we actually have pending references
// note this will also print out internal live objects to the debug console
debug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL);
}
SAFE_RELEASE(debug)
}
#endif
if (references)
{
ERROR_LOG(VIDEO, "Unreleased references: %i.", references);
}
else
{
NOTICE_LOG(VIDEO, "Successfully released all device references!");
}
device = nullptr;
if (references)
{
ERROR_LOG(VIDEO, "Unreleased references: %i.", references);
}
else
{
NOTICE_LOG(VIDEO, "Successfully released all device references!");
}
device = nullptr;
// unload DLLs
UnloadD3D();
UnloadDXGI();
// unload DLLs
UnloadD3D();
UnloadDXGI();
}
const char* VertexShaderVersionString()
{
if (featlevel == D3D_FEATURE_LEVEL_11_0) return "vs_5_0";
else if (featlevel == D3D_FEATURE_LEVEL_10_1) return "vs_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "vs_4_0";
if (featlevel == D3D_FEATURE_LEVEL_11_0)
return "vs_5_0";
else if (featlevel == D3D_FEATURE_LEVEL_10_1)
return "vs_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/
return "vs_4_0";
}
const char* GeometryShaderVersionString()
{
if (featlevel == D3D_FEATURE_LEVEL_11_0) return "gs_5_0";
else if (featlevel == D3D_FEATURE_LEVEL_10_1) return "gs_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "gs_4_0";
if (featlevel == D3D_FEATURE_LEVEL_11_0)
return "gs_5_0";
else if (featlevel == D3D_FEATURE_LEVEL_10_1)
return "gs_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/
return "gs_4_0";
}
const char* PixelShaderVersionString()
{
if (featlevel == D3D_FEATURE_LEVEL_11_0) return "ps_5_0";
else if (featlevel == D3D_FEATURE_LEVEL_10_1) return "ps_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "ps_4_0";
if (featlevel == D3D_FEATURE_LEVEL_11_0)
return "ps_5_0";
else if (featlevel == D3D_FEATURE_LEVEL_10_1)
return "ps_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/
return "ps_4_0";
}
D3DTexture2D* &GetBackBuffer() { return backbuf; }
unsigned int GetBackBufferWidth() { return xres; }
unsigned int GetBackBufferHeight() { return yres; }
D3DTexture2D*& GetBackBuffer()
{
return backbuf;
}
unsigned int GetBackBufferWidth()
{
return xres;
}
unsigned int GetBackBufferHeight()
{
return yres;
}
bool BGRATexturesSupported() { return bgra_textures_supported; }
bool BGRATexturesSupported()
{
return bgra_textures_supported;
}
// Returns the maximum width/height of a texture. This value only depends upon the feature level in DX11
// Returns the maximum width/height of a texture. This value only depends upon the feature level in
// DX11
unsigned int GetMaxTextureSize()
{
switch (featlevel)
{
case D3D_FEATURE_LEVEL_11_0:
return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
switch (featlevel)
{
case D3D_FEATURE_LEVEL_11_0:
return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0:
return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0:
return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
case D3D_FEATURE_LEVEL_9_3:
return 4096;
case D3D_FEATURE_LEVEL_9_3:
return 4096;
case D3D_FEATURE_LEVEL_9_2:
case D3D_FEATURE_LEVEL_9_1:
return 2048;
case D3D_FEATURE_LEVEL_9_2:
case D3D_FEATURE_LEVEL_9_1:
return 2048;
default:
return 0;
}
default:
return 0;
}
}
void Reset()
{
// release all back buffer references
SAFE_RELEASE(backbuf);
// release all back buffer references
SAFE_RELEASE(backbuf);
// resize swapchain buffers
RECT client;
GetClientRect(hWnd, &client);
xres = client.right - client.left;
yres = client.bottom - client.top;
D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
// resize swapchain buffers
RECT client;
GetClientRect(hWnd, &client);
xres = client.right - client.left;
yres = client.bottom - client.top;
D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
// recreate back buffer texture
ID3D11Texture2D* buf;
HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
if (FAILED(hr))
{
MessageBox(hWnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
SAFE_RELEASE(device);
SAFE_RELEASE(context);
SAFE_RELEASE(swapchain);
return;
}
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
SAFE_RELEASE(buf);
CHECK(backbuf!=nullptr, "Create back buffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
// recreate back buffer texture
ID3D11Texture2D* buf;
HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
if (FAILED(hr))
{
MessageBox(hWnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"),
MB_OK | MB_ICONERROR);
SAFE_RELEASE(device);
SAFE_RELEASE(context);
SAFE_RELEASE(swapchain);
return;
}
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
SAFE_RELEASE(buf);
CHECK(backbuf != nullptr, "Create back buffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
}
bool BeginFrame()
{
if (bFrameInProgress)
{
PanicAlert("BeginFrame called although a frame is already in progress");
return false;
}
bFrameInProgress = true;
return (device != nullptr);
if (bFrameInProgress)
{
PanicAlert("BeginFrame called although a frame is already in progress");
return false;
}
bFrameInProgress = true;
return (device != nullptr);
}
void EndFrame()
{
if (!bFrameInProgress)
{
PanicAlert("EndFrame called although no frame is in progress");
return;
}
bFrameInProgress = false;
if (!bFrameInProgress)
{
PanicAlert("EndFrame called although no frame is in progress");
return;
}
bFrameInProgress = false;
}
void Present()
{
// TODO: Is 1 the correct value for vsyncing?
swapchain->Present((UINT)g_ActiveConfig.IsVSync(), 0);
// TODO: Is 1 the correct value for vsyncing?
swapchain->Present((UINT)g_ActiveConfig.IsVSync(), 0);
}
HRESULT SetFullscreenState(bool enable_fullscreen)
{
return swapchain->SetFullscreenState(enable_fullscreen, nullptr);
return swapchain->SetFullscreenState(enable_fullscreen, nullptr);
}
HRESULT GetFullscreenState(bool* fullscreen_state)
{
if (fullscreen_state == nullptr)
{
return E_POINTER;
}
if (fullscreen_state == nullptr)
{
return E_POINTER;
}
BOOL state;
HRESULT hr = swapchain->GetFullscreenState(&state, nullptr);
*fullscreen_state = !!state;
return hr;
BOOL state;
HRESULT hr = swapchain->GetFullscreenState(&state, nullptr);
*fullscreen_state = !!state;
return hr;
}
} // namespace D3D

View File

@ -13,17 +13,33 @@
namespace DX11
{
#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = nullptr; }
#define SAFE_DELETE(x) { delete (x); (x) = nullptr; }
#define SAFE_DELETE_ARRAY(x) { delete[] (x); (x) = nullptr; }
#define CHECK(cond, Message, ...) if (!(cond)) { PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); }
#define SAFE_RELEASE(x) \
{ \
if (x) \
(x)->Release(); \
(x) = nullptr; \
}
#define SAFE_DELETE(x) \
{ \
delete (x); \
(x) = nullptr; \
}
#define SAFE_DELETE_ARRAY(x) \
{ \
delete[](x); \
(x) = nullptr; \
}
#define CHECK(cond, Message, ...) \
if (!(cond)) \
{ \
PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, \
__VA_ARGS__); \
}
class D3DTexture2D;
namespace D3D
{
HRESULT LoadDXGI();
HRESULT LoadD3D();
HRESULT LoadD3DCompiler();
@ -49,7 +65,7 @@ void Present();
unsigned int GetBackBufferWidth();
unsigned int GetBackBufferHeight();
D3DTexture2D* &GetBackBuffer();
D3DTexture2D*& GetBackBuffer();
const char* PixelShaderVersionString();
const char* GeometryShaderVersionString();
const char* VertexShaderVersionString();
@ -66,39 +82,41 @@ HRESULT GetFullscreenState(bool* fullscreen_state);
template <typename T>
void SetDebugObjectName(T resource, const char* name)
{
static_assert(std::is_convertible<T, ID3D11DeviceChild*>::value,
"resource must be convertible to ID3D11DeviceChild*");
static_assert(std::is_convertible<T, ID3D11DeviceChild*>::value,
"resource must be convertible to ID3D11DeviceChild*");
#if defined(_DEBUG) || defined(DEBUGFAST)
if (resource)
resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)(name ? strlen(name) : 0), name);
if (resource)
resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)(name ? strlen(name) : 0), name);
#endif
}
template <typename T>
std::string GetDebugObjectName(T resource)
{
static_assert(std::is_convertible<T, ID3D11DeviceChild*>::value,
"resource must be convertible to ID3D11DeviceChild*");
std::string name;
static_assert(std::is_convertible<T, ID3D11DeviceChild*>::value,
"resource must be convertible to ID3D11DeviceChild*");
std::string name;
#if defined(_DEBUG) || defined(DEBUGFAST)
if (resource)
{
UINT size = 0;
resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); //get required size
name.resize(size);
resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, const_cast<char*>(name.data()));
}
if (resource)
{
UINT size = 0;
resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); // get required size
name.resize(size);
resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, const_cast<char*>(name.data()));
}
#endif
return name;
return name;
}
} // namespace D3D
typedef HRESULT (WINAPI* CREATEDXGIFACTORY)(REFIID, void**);
typedef HRESULT(WINAPI* CREATEDXGIFACTORY)(REFIID, void**);
extern CREATEDXGIFACTORY PCreateDXGIFactory;
typedef HRESULT (WINAPI* D3D11CREATEDEVICE)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
typedef HRESULT(WINAPI* D3D11CREATEDEVICE)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT,
CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**,
D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
typedef HRESULT (WINAPI* D3DREFLECT)(LPCVOID, SIZE_T, REFIID, void**);
typedef HRESULT(WINAPI* D3DREFLECT)(LPCVOID, SIZE_T, REFIID, void**);
extern D3DREFLECT PD3DReflect;
extern pD3DCompile PD3DCompile;

View File

@ -8,50 +8,53 @@
namespace DX11
{
D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data) : ref(1), size(blob_size), blob(nullptr)
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);
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();
blob = d3dblob;
data = (u8*)blob->GetBufferPointer();
size = (unsigned int)blob->GetBufferSize();
d3dblob->AddRef();
}
D3DBlob::~D3DBlob()
{
if (blob) blob->Release();
else delete[] data;
if (blob)
blob->Release();
else
delete[] data;
}
void D3DBlob::AddRef()
{
++ref;
++ref;
}
unsigned int D3DBlob::Release()
{
if (--ref == 0)
{
delete this;
return 0;
}
return ref;
if (--ref == 0)
{
delete this;
return 0;
}
return ref;
}
unsigned int D3DBlob::Size() const
{
return size;
return size;
}
u8* D3DBlob::Data()
{
return data;
return data;
}
} // namespace DX11

View File

@ -10,31 +10,30 @@ 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);
// 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);
// d3dblob will be AddRef'd
D3DBlob(ID3D10Blob* d3dblob);
void AddRef();
unsigned int Release();
void AddRef();
unsigned int Release();
unsigned int Size() const;
u8* Data();
unsigned int Size() const;
u8* Data();
private:
~D3DBlob();
~D3DBlob();
unsigned int ref;
unsigned int size;
unsigned int ref;
unsigned int size;
u8* data;
ID3D10Blob* blob;
u8* data;
ID3D10Blob* blob;
};
} // namespace

View File

@ -6,218 +6,224 @@
#include <string>
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Common/Logging/Log.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, unsigned int len)
{
ID3D11VertexShader* v_shader;
HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, nullptr, &v_shader);
if (FAILED(hr))
return nullptr;
ID3D11VertexShader* v_shader;
HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, nullptr, &v_shader);
if (FAILED(hr))
return nullptr;
return v_shader;
return v_shader;
}
// code->bytecode
bool CompileVertexShader(const std::string& code, D3DBlob** blob)
{
ID3D10Blob* shaderBuffer = nullptr;
ID3D10Blob* errorBuffer = nullptr;
ID3D10Blob* shaderBuffer = nullptr;
ID3D10Blob* errorBuffer = nullptr;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG;
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;
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\n",
(const char*)errorBuffer->GetBufferPointer());
}
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\n",
(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;
OpenFStream(file, filename, std::ios_base::out);
file << code;
file.close();
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;
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());
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);
*blob = nullptr;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
// bytecode->shader
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len)
{
ID3D11GeometryShader* g_shader;
HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, nullptr, &g_shader);
if (FAILED(hr))
return nullptr;
ID3D11GeometryShader* g_shader;
HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, nullptr, &g_shader);
if (FAILED(hr))
return nullptr;
return g_shader;
return g_shader;
}
// code->bytecode
bool CompileGeometryShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines)
bool CompileGeometryShader(const std::string& code, D3DBlob** blob,
const D3D_SHADER_MACRO* pDefines)
{
ID3D10Blob* shaderBuffer = nullptr;
ID3D10Blob* errorBuffer = nullptr;
ID3D10Blob* shaderBuffer = nullptr;
ID3D10Blob* errorBuffer = nullptr;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG;
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;
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);
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\n",
(const char*)errorBuffer->GetBufferPointer());
}
if (errorBuffer)
{
INFO_LOG(VIDEO, "Geometry shader compiler messages:\n%s\n",
(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;
OpenFStream(file, filename, std::ios_base::out);
file << code;
file.close();
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;
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());
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);
*blob = nullptr;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
// bytecode->shader
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int 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;
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;
ID3D10Blob* shaderBuffer = nullptr;
ID3D10Blob* errorBuffer = nullptr;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_DEBUG;
UINT flags = D3D10_SHADER_DEBUG;
#else
UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3;
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);
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 (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;
OpenFStream(file, filename, std::ios_base::out);
file << code;
file.close();
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;
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());
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();
}
*blob = nullptr;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
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;
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)
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;
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;
D3DBlob* blob = nullptr;
CompilePixelShader(code, &blob);
if (blob)
{
ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob);
blob->Release();
return p_shader;
}
return nullptr;
}
} // namespace

View File

@ -14,44 +14,53 @@ struct ID3D11VertexShader;
namespace DX11
{
namespace D3D
{
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int 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);
// 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);
// 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);
// 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);
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 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 ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code)
{
return CompileAndCreateVertexShader((const char*)code->Data());
}
inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code)
{
return CompileAndCreateVertexShader((const char*)code->Data());
}
inline ID3D11GeometryShader* CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = nullptr)
{
return CompileAndCreateGeometryShader((const char*)code->Data(), pDefines);
}
inline ID3D11GeometryShader*
CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = nullptr)
{
return CompileAndCreateGeometryShader((const char*)code->Data(), pDefines);
}
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code)
{
return CompileAndCreatePixelShader((const char*)code->Data());
}
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code)
{
return CompileAndCreatePixelShader((const char*)code->Data());
}
}
} // namespace DX11

View File

@ -6,8 +6,8 @@
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DState.h"
@ -15,503 +15,520 @@
namespace DX11
{
namespace D3D
{
StateManager* stateman;
template<typename T> AutoState<T>::AutoState(const T* object) : state(object)
template <typename T>
AutoState<T>::AutoState(const T* object) : state(object)
{
((IUnknown*)state)->AddRef();
((IUnknown*)state)->AddRef();
}
template<typename T> AutoState<T>::AutoState(const AutoState<T> &source)
template <typename T>
AutoState<T>::AutoState(const AutoState<T>& source)
{
state = source.GetPtr();
((T*)state)->AddRef();
state = source.GetPtr();
((T*)state)->AddRef();
}
template<typename T> AutoState<T>::~AutoState()
template <typename T>
AutoState<T>::~AutoState()
{
if (state) ((T*)state)->Release();
state = nullptr;
if (state)
((T*)state)->Release();
state = nullptr;
}
StateManager::StateManager()
: m_currentBlendState(nullptr)
, m_currentDepthState(nullptr)
, m_currentRasterizerState(nullptr)
, m_dirtyFlags(~0u)
, m_pending()
, m_current()
: m_currentBlendState(nullptr), m_currentDepthState(nullptr), m_currentRasterizerState(nullptr),
m_dirtyFlags(~0u), m_pending(), m_current()
{
}
void StateManager::PushBlendState(const ID3D11BlendState* state) { m_blendStates.push(AutoBlendState(state)); }
void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { m_depthStates.push(AutoDepthStencilState(state)); }
void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { m_rasterizerStates.push(AutoRasterizerState(state)); }
void StateManager::PopBlendState() { m_blendStates.pop(); }
void StateManager::PopDepthState() { m_depthStates.pop(); }
void StateManager::PopRasterizerState() { m_rasterizerStates.pop(); }
void StateManager::PushBlendState(const ID3D11BlendState* state)
{
m_blendStates.push(AutoBlendState(state));
}
void StateManager::PushDepthState(const ID3D11DepthStencilState* state)
{
m_depthStates.push(AutoDepthStencilState(state));
}
void StateManager::PushRasterizerState(const ID3D11RasterizerState* state)
{
m_rasterizerStates.push(AutoRasterizerState(state));
}
void StateManager::PopBlendState()
{
m_blendStates.pop();
}
void StateManager::PopDepthState()
{
m_depthStates.pop();
}
void StateManager::PopRasterizerState()
{
m_rasterizerStates.pop();
}
void StateManager::Apply()
{
if (!m_blendStates.empty())
{
if (m_currentBlendState != m_blendStates.top().GetPtr())
{
m_currentBlendState = (ID3D11BlendState*)m_blendStates.top().GetPtr();
D3D::context->OMSetBlendState(m_currentBlendState, nullptr, 0xFFFFFFFF);
}
}
else ERROR_LOG(VIDEO, "Tried to apply without blend state!");
if (!m_blendStates.empty())
{
if (m_currentBlendState != m_blendStates.top().GetPtr())
{
m_currentBlendState = (ID3D11BlendState*)m_blendStates.top().GetPtr();
D3D::context->OMSetBlendState(m_currentBlendState, nullptr, 0xFFFFFFFF);
}
}
else
ERROR_LOG(VIDEO, "Tried to apply without blend state!");
if (!m_depthStates.empty())
{
if (m_currentDepthState != m_depthStates.top().GetPtr())
{
m_currentDepthState = (ID3D11DepthStencilState*)m_depthStates.top().GetPtr();
D3D::context->OMSetDepthStencilState(m_currentDepthState, 0);
}
}
else ERROR_LOG(VIDEO, "Tried to apply without depth state!");
if (!m_depthStates.empty())
{
if (m_currentDepthState != m_depthStates.top().GetPtr())
{
m_currentDepthState = (ID3D11DepthStencilState*)m_depthStates.top().GetPtr();
D3D::context->OMSetDepthStencilState(m_currentDepthState, 0);
}
}
else
ERROR_LOG(VIDEO, "Tried to apply without depth state!");
if (!m_rasterizerStates.empty())
{
if (m_currentRasterizerState != m_rasterizerStates.top().GetPtr())
{
m_currentRasterizerState = (ID3D11RasterizerState*)m_rasterizerStates.top().GetPtr();
D3D::context->RSSetState(m_currentRasterizerState);
}
}
else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!");
if (!m_rasterizerStates.empty())
{
if (m_currentRasterizerState != m_rasterizerStates.top().GetPtr())
{
m_currentRasterizerState = (ID3D11RasterizerState*)m_rasterizerStates.top().GetPtr();
D3D::context->RSSetState(m_currentRasterizerState);
}
}
else
ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!");
if (!m_dirtyFlags)
{
return;
}
if (!m_dirtyFlags)
{
return;
}
int textureMaskShift = LeastSignificantSetBit((u32)DirtyFlag_Texture0);
int samplerMaskShift = LeastSignificantSetBit((u32)DirtyFlag_Sampler0);
int textureMaskShift = LeastSignificantSetBit((u32)DirtyFlag_Texture0);
int samplerMaskShift = 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;
u32 dirtyConstants = m_dirtyFlags & (DirtyFlag_PixelConstants | DirtyFlag_VertexConstants | DirtyFlag_GeometryConstants);
u32 dirtyShaders = m_dirtyFlags & (DirtyFlag_PixelShader | DirtyFlag_VertexShader | DirtyFlag_GeometryShader);
u32 dirtyBuffers = m_dirtyFlags & (DirtyFlag_VertexBuffer | DirtyFlag_IndexBuffer);
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 =
m_dirtyFlags & (DirtyFlag_PixelShader | DirtyFlag_VertexShader | DirtyFlag_GeometryShader);
u32 dirtyBuffers = m_dirtyFlags & (DirtyFlag_VertexBuffer | DirtyFlag_IndexBuffer);
if (dirtyConstants)
{
if (m_current.pixelConstants[0] != m_pending.pixelConstants[0] ||
m_current.pixelConstants[1] != m_pending.pixelConstants[1])
{
D3D::context->PSSetConstantBuffers(0, m_pending.pixelConstants[1] ? 2 : 1, m_pending.pixelConstants);
m_current.pixelConstants[0] = m_pending.pixelConstants[0];
m_current.pixelConstants[1] = m_pending.pixelConstants[1];
}
if (dirtyConstants)
{
if (m_current.pixelConstants[0] != m_pending.pixelConstants[0] ||
m_current.pixelConstants[1] != m_pending.pixelConstants[1])
{
D3D::context->PSSetConstantBuffers(0, m_pending.pixelConstants[1] ? 2 : 1,
m_pending.pixelConstants);
m_current.pixelConstants[0] = m_pending.pixelConstants[0];
m_current.pixelConstants[1] = m_pending.pixelConstants[1];
}
if (m_current.vertexConstants != m_pending.vertexConstants)
{
D3D::context->VSSetConstantBuffers(0, 1, &m_pending.vertexConstants);
m_current.vertexConstants = m_pending.vertexConstants;
}
if (m_current.vertexConstants != m_pending.vertexConstants)
{
D3D::context->VSSetConstantBuffers(0, 1, &m_pending.vertexConstants);
m_current.vertexConstants = m_pending.vertexConstants;
}
if (m_current.geometryConstants != m_pending.geometryConstants)
{
D3D::context->GSSetConstantBuffers(0, 1, &m_pending.geometryConstants);
m_current.geometryConstants = m_pending.geometryConstants;
}
}
if (m_current.geometryConstants != m_pending.geometryConstants)
{
D3D::context->GSSetConstantBuffers(0, 1, &m_pending.geometryConstants);
m_current.geometryConstants = m_pending.geometryConstants;
}
}
if (dirtyBuffers || (m_dirtyFlags & DirtyFlag_InputAssembler))
{
if (m_current.vertexBuffer != m_pending.vertexBuffer ||
m_current.vertexBufferStride != m_pending.vertexBufferStride ||
m_current.vertexBufferOffset != m_pending.vertexBufferOffset)
{
D3D::context->IASetVertexBuffers(0, 1, &m_pending.vertexBuffer, &m_pending.vertexBufferStride, &m_pending.vertexBufferOffset);
m_current.vertexBuffer = m_pending.vertexBuffer;
m_current.vertexBufferStride = m_pending.vertexBufferStride;
m_current.vertexBufferOffset = m_pending.vertexBufferOffset;
}
if (dirtyBuffers || (m_dirtyFlags & DirtyFlag_InputAssembler))
{
if (m_current.vertexBuffer != m_pending.vertexBuffer ||
m_current.vertexBufferStride != m_pending.vertexBufferStride ||
m_current.vertexBufferOffset != m_pending.vertexBufferOffset)
{
D3D::context->IASetVertexBuffers(0, 1, &m_pending.vertexBuffer, &m_pending.vertexBufferStride,
&m_pending.vertexBufferOffset);
m_current.vertexBuffer = m_pending.vertexBuffer;
m_current.vertexBufferStride = m_pending.vertexBufferStride;
m_current.vertexBufferOffset = m_pending.vertexBufferOffset;
}
if (m_current.indexBuffer != m_pending.indexBuffer)
{
D3D::context->IASetIndexBuffer(m_pending.indexBuffer, DXGI_FORMAT_R16_UINT, 0);
m_current.indexBuffer = m_pending.indexBuffer;
}
if (m_current.indexBuffer != m_pending.indexBuffer)
{
D3D::context->IASetIndexBuffer(m_pending.indexBuffer, DXGI_FORMAT_R16_UINT, 0);
m_current.indexBuffer = m_pending.indexBuffer;
}
if (m_current.topology != m_pending.topology)
{
D3D::context->IASetPrimitiveTopology(m_pending.topology);
m_current.topology = m_pending.topology;
}
if (m_current.topology != m_pending.topology)
{
D3D::context->IASetPrimitiveTopology(m_pending.topology);
m_current.topology = m_pending.topology;
}
if (m_current.inputLayout != m_pending.inputLayout)
{
D3D::context->IASetInputLayout(m_pending.inputLayout);
m_current.inputLayout = m_pending.inputLayout;
}
}
if (m_current.inputLayout != m_pending.inputLayout)
{
D3D::context->IASetInputLayout(m_pending.inputLayout);
m_current.inputLayout = m_pending.inputLayout;
}
}
while (dirtyTextures)
{
int index = 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];
}
while (dirtyTextures)
{
int index = 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);
}
dirtyTextures &= ~(1 << index);
}
while (dirtySamplers)
{
int index = 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];
}
while (dirtySamplers)
{
int index = 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);
}
dirtySamplers &= ~(1 << index);
}
if (dirtyShaders)
{
if (m_current.pixelShader != m_pending.pixelShader)
{
D3D::context->PSSetShader(m_pending.pixelShader, nullptr, 0);
m_current.pixelShader = m_pending.pixelShader;
}
if (dirtyShaders)
{
if (m_current.pixelShader != m_pending.pixelShader)
{
D3D::context->PSSetShader(m_pending.pixelShader, nullptr, 0);
m_current.pixelShader = m_pending.pixelShader;
}
if (m_current.vertexShader != m_pending.vertexShader)
{
D3D::context->VSSetShader(m_pending.vertexShader, nullptr, 0);
m_current.vertexShader = m_pending.vertexShader;
}
if (m_current.vertexShader != m_pending.vertexShader)
{
D3D::context->VSSetShader(m_pending.vertexShader, nullptr, 0);
m_current.vertexShader = m_pending.vertexShader;
}
if (m_current.geometryShader != m_pending.geometryShader)
{
D3D::context->GSSetShader(m_pending.geometryShader, nullptr, 0);
m_current.geometryShader = m_pending.geometryShader;
}
}
if (m_current.geometryShader != m_pending.geometryShader)
{
D3D::context->GSSetShader(m_pending.geometryShader, nullptr, 0);
m_current.geometryShader = m_pending.geometryShader;
}
}
m_dirtyFlags = 0;
m_dirtyFlags = 0;
}
u32 StateManager::UnsetTexture(ID3D11ShaderResourceView* srv)
{
u32 mask = 0;
u32 mask = 0;
for (u32 index = 0; index < 8; ++index)
{
if (m_current.textures[index] == srv)
{
SetTexture(index, nullptr);
mask |= 1 << index;
}
}
for (u32 index = 0; index < 8; ++index)
{
if (m_current.textures[index] == srv)
{
SetTexture(index, nullptr);
mask |= 1 << index;
}
}
return mask;
return mask;
}
void StateManager::SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv)
{
while (textureSlotMask)
{
int index = LeastSignificantSetBit(textureSlotMask);
SetTexture(index, srv);
textureSlotMask &= ~(1 << index);
}
while (textureSlotMask)
{
int index = LeastSignificantSetBit(textureSlotMask);
SetTexture(index, srv);
textureSlotMask &= ~(1 << index);
}
}
} // namespace D3D
ID3D11SamplerState* StateCache::Get(SamplerState state)
{
auto it = m_sampler.find(state.packed);
auto it = m_sampler.find(state.packed);
if (it != m_sampler.end())
{
return it->second;
}
if (it != m_sampler.end())
{
return it->second;
}
const unsigned int d3dMipFilters[4] =
{
TexMode0::TEXF_NONE,
TexMode0::TEXF_POINT,
TexMode0::TEXF_LINEAR,
TexMode0::TEXF_NONE, //reserved
};
const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] =
{
D3D11_TEXTURE_ADDRESS_CLAMP,
D3D11_TEXTURE_ADDRESS_WRAP,
D3D11_TEXTURE_ADDRESS_MIRROR,
D3D11_TEXTURE_ADDRESS_WRAP //reserved
};
const unsigned int d3dMipFilters[4] = {
TexMode0::TEXF_NONE, TexMode0::TEXF_POINT, TexMode0::TEXF_LINEAR,
TexMode0::TEXF_NONE, // reserved
};
const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] = {
D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_MIRROR,
D3D11_TEXTURE_ADDRESS_WRAP // reserved
};
D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
unsigned int mip = d3dMipFilters[state.min_filter & 3];
unsigned int mip = d3dMipFilters[state.min_filter & 3];
if (state.max_anisotropy > 1 && !SamplerCommon::IsBpTexMode0PointFiltering(state))
{
sampdc.Filter = D3D11_FILTER_ANISOTROPIC;
sampdc.MaxAnisotropy = (u32)state.max_anisotropy;
}
else if (state.min_filter & 4) // linear min filter
{
if (state.mag_filter) // linear mag filter
{
if (mip == TexMode0::TEXF_NONE)
sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
else if (mip == TexMode0::TEXF_POINT)
sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
else if (mip == TexMode0::TEXF_LINEAR)
sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
}
else // point mag filter
{
if (mip == TexMode0::TEXF_NONE)
sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
else if (mip == TexMode0::TEXF_POINT)
sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
else if (mip == TexMode0::TEXF_LINEAR)
sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
}
}
else // point min filter
{
if (state.mag_filter) // linear mag filter
{
if (mip == TexMode0::TEXF_NONE)
sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
else if (mip == TexMode0::TEXF_POINT)
sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
else if (mip == TexMode0::TEXF_LINEAR)
sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
}
else // point mag filter
{
if (mip == TexMode0::TEXF_NONE)
sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
else if (mip == TexMode0::TEXF_POINT)
sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
else if (mip == TexMode0::TEXF_LINEAR)
sampdc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
}
}
if (state.max_anisotropy > 1 && !SamplerCommon::IsBpTexMode0PointFiltering(state))
{
sampdc.Filter = D3D11_FILTER_ANISOTROPIC;
sampdc.MaxAnisotropy = (u32)state.max_anisotropy;
}
else if (state.min_filter & 4) // linear min filter
{
if (state.mag_filter) // linear mag filter
{
if (mip == TexMode0::TEXF_NONE)
sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
else if (mip == TexMode0::TEXF_POINT)
sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
else if (mip == TexMode0::TEXF_LINEAR)
sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
}
else // point mag filter
{
if (mip == TexMode0::TEXF_NONE)
sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
else if (mip == TexMode0::TEXF_POINT)
sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
else if (mip == TexMode0::TEXF_LINEAR)
sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
}
}
else // point min filter
{
if (state.mag_filter) // linear mag filter
{
if (mip == TexMode0::TEXF_NONE)
sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
else if (mip == TexMode0::TEXF_POINT)
sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
else if (mip == TexMode0::TEXF_LINEAR)
sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
}
else // point mag filter
{
if (mip == TexMode0::TEXF_NONE)
sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
else if (mip == TexMode0::TEXF_POINT)
sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
else if (mip == TexMode0::TEXF_LINEAR)
sampdc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
}
}
sampdc.AddressU = d3dClamps[state.wrap_s];
sampdc.AddressV = d3dClamps[state.wrap_t];
sampdc.AddressU = d3dClamps[state.wrap_s];
sampdc.AddressV = d3dClamps[state.wrap_t];
sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f;
sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD);
sampdc.MipLODBias = (s32)state.lod_bias / 32.0f;
sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f;
sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD);
sampdc.MipLODBias = (s32)state.lod_bias / 32.0f;
ID3D11SamplerState* res = nullptr;
ID3D11SamplerState* res = nullptr;
HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res);
if (FAILED(hr))
PanicAlert("Fail %s %d\n", __FILE__, __LINE__);
HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res);
if (FAILED(hr))
PanicAlert("Fail %s %d\n", __FILE__, __LINE__);
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline");
m_sampler.emplace(state.packed, res);
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "sampler state used to emulate the GX pipeline");
m_sampler.emplace(state.packed, res);
return res;
return res;
}
ID3D11BlendState* StateCache::Get(BlendState state)
{
if (!state.blend_enable)
{
state.src_blend = D3D11_BLEND_ONE;
state.dst_blend = D3D11_BLEND_ZERO;
state.blend_op = D3D11_BLEND_OP_ADD;
state.use_dst_alpha = false;
}
if (!state.blend_enable)
{
state.src_blend = D3D11_BLEND_ONE;
state.dst_blend = D3D11_BLEND_ZERO;
state.blend_op = D3D11_BLEND_OP_ADD;
state.use_dst_alpha = false;
}
auto it = m_blend.find(state.packed);
auto it = m_blend.find(state.packed);
if (it != m_blend.end())
return it->second;
if (it != m_blend.end())
return it->second;
D3D11_BLEND_DESC blenddc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
D3D11_BLEND_DESC blenddc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
blenddc.AlphaToCoverageEnable = FALSE;
blenddc.IndependentBlendEnable = FALSE;
blenddc.RenderTarget[0].BlendEnable = state.blend_enable;
blenddc.RenderTarget[0].RenderTargetWriteMask = (u32)state.write_mask;
blenddc.RenderTarget[0].SrcBlend = state.src_blend;
blenddc.RenderTarget[0].DestBlend = state.dst_blend;
blenddc.RenderTarget[0].BlendOp = state.blend_op;
blenddc.RenderTarget[0].SrcBlendAlpha = state.src_blend;
blenddc.RenderTarget[0].DestBlendAlpha = state.dst_blend;
blenddc.RenderTarget[0].BlendOpAlpha = state.blend_op;
blenddc.AlphaToCoverageEnable = FALSE;
blenddc.IndependentBlendEnable = FALSE;
blenddc.RenderTarget[0].BlendEnable = state.blend_enable;
blenddc.RenderTarget[0].RenderTargetWriteMask = (u32)state.write_mask;
blenddc.RenderTarget[0].SrcBlend = state.src_blend;
blenddc.RenderTarget[0].DestBlend = state.dst_blend;
blenddc.RenderTarget[0].BlendOp = state.blend_op;
blenddc.RenderTarget[0].SrcBlendAlpha = state.src_blend;
blenddc.RenderTarget[0].DestBlendAlpha = state.dst_blend;
blenddc.RenderTarget[0].BlendOpAlpha = state.blend_op;
if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_COLOR)
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_COLOR)
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_DEST_COLOR)
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA;
else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_DEST_COLOR)
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
else
blenddc.RenderTarget[0].SrcBlendAlpha = blenddc.RenderTarget[0].SrcBlend;
if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_COLOR)
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_COLOR)
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_DEST_COLOR)
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA;
else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_DEST_COLOR)
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
else
blenddc.RenderTarget[0].SrcBlendAlpha = blenddc.RenderTarget[0].SrcBlend;
if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_COLOR)
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA;
else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_COLOR)
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_DEST_COLOR)
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_DEST_COLOR)
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
else
blenddc.RenderTarget[0].DestBlendAlpha = blenddc.RenderTarget[0].DestBlend;
if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_COLOR)
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA;
else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_COLOR)
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_DEST_COLOR)
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_DEST_COLOR)
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
else
blenddc.RenderTarget[0].DestBlendAlpha = blenddc.RenderTarget[0].DestBlend;
if (state.use_dst_alpha)
{
// Colors should blend against SRC1_ALPHA
if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_ALPHA)
blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC1_ALPHA;
else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_ALPHA)
blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC1_ALPHA;
if (state.use_dst_alpha)
{
// Colors should blend against SRC1_ALPHA
if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_SRC_ALPHA)
blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC1_ALPHA;
else if (blenddc.RenderTarget[0].SrcBlend == D3D11_BLEND_INV_SRC_ALPHA)
blenddc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_SRC1_ALPHA;
// Colors should blend against SRC1_ALPHA
if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_ALPHA)
blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA;
else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_ALPHA)
blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_ALPHA;
// Colors should blend against SRC1_ALPHA
if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_SRC_ALPHA)
blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA;
else if (blenddc.RenderTarget[0].DestBlend == D3D11_BLEND_INV_SRC_ALPHA)
blenddc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_ALPHA;
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blenddc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
}
blenddc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blenddc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blenddc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
}
ID3D11BlendState* res = nullptr;
ID3D11BlendState* res = nullptr;
HRESULT hr = D3D::device->CreateBlendState(&blenddc, &res);
if (FAILED(hr))
PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
HRESULT hr = D3D::device->CreateBlendState(&blenddc, &res);
if (FAILED(hr))
PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline");
m_blend.emplace(state.packed, res);
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "blend state used to emulate the GX pipeline");
m_blend.emplace(state.packed, res);
return res;
return res;
}
ID3D11RasterizerState* StateCache::Get(RasterizerState state)
{
auto it = m_raster.find(state.packed);
auto it = m_raster.find(state.packed);
if (it != m_raster.end())
return it->second;
if (it != m_raster.end())
return it->second;
D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID,
state.cull_mode,
false, 0, 0.f, 0, true, true, false, false);
D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, state.cull_mode, false, 0,
0.f, 0, true, true, false, false);
ID3D11RasterizerState* res = nullptr;
ID3D11RasterizerState* res = nullptr;
HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res);
if (FAILED(hr))
PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__);
HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res);
if (FAILED(hr))
PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__);
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "rasterizer state used to emulate the GX pipeline");
m_raster.emplace(state.packed, res);
D3D::SetDebugObjectName((ID3D11DeviceChild*)res,
"rasterizer state used to emulate the GX pipeline");
m_raster.emplace(state.packed, res);
return res;
return res;
}
ID3D11DepthStencilState* StateCache::Get(ZMode state)
{
auto it = m_depth.find(state.hex);
auto it = m_depth.find(state.hex);
if (it != m_depth.end())
return it->second;
if (it != m_depth.end())
return it->second;
D3D11_DEPTH_STENCIL_DESC depthdc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
D3D11_DEPTH_STENCIL_DESC depthdc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
depthdc.DepthEnable = TRUE;
depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthdc.DepthFunc = D3D11_COMPARISON_GREATER;
depthdc.StencilEnable = FALSE;
depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
depthdc.DepthEnable = TRUE;
depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthdc.DepthFunc = D3D11_COMPARISON_GREATER;
depthdc.StencilEnable = FALSE;
depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] =
{
D3D11_COMPARISON_NEVER,
D3D11_COMPARISON_GREATER,
D3D11_COMPARISON_EQUAL,
D3D11_COMPARISON_GREATER_EQUAL,
D3D11_COMPARISON_LESS,
D3D11_COMPARISON_NOT_EQUAL,
D3D11_COMPARISON_LESS_EQUAL,
D3D11_COMPARISON_ALWAYS
};
const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = {
D3D11_COMPARISON_NEVER, D3D11_COMPARISON_GREATER, D3D11_COMPARISON_EQUAL,
D3D11_COMPARISON_GREATER_EQUAL, D3D11_COMPARISON_LESS, D3D11_COMPARISON_NOT_EQUAL,
D3D11_COMPARISON_LESS_EQUAL, D3D11_COMPARISON_ALWAYS};
if (state.testenable)
{
depthdc.DepthEnable = TRUE;
depthdc.DepthWriteMask = state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
depthdc.DepthFunc = d3dCmpFuncs[state.func];
}
else
{
// if the test is disabled write is disabled too
depthdc.DepthEnable = FALSE;
depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
}
if (state.testenable)
{
depthdc.DepthEnable = TRUE;
depthdc.DepthWriteMask =
state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
depthdc.DepthFunc = d3dCmpFuncs[state.func];
}
else
{
// if the test is disabled write is disabled too
depthdc.DepthEnable = FALSE;
depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
}
ID3D11DepthStencilState* res = nullptr;
ID3D11DepthStencilState* res = nullptr;
HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res);
if (SUCCEEDED(hr))
D3D::SetDebugObjectName((ID3D11DeviceChild*)res, "depth-stencil state used to emulate the GX pipeline");
else
PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__);
HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res);
if (SUCCEEDED(hr))
D3D::SetDebugObjectName((ID3D11DeviceChild*)res,
"depth-stencil state used to emulate the GX pipeline");
else
PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__);
m_depth.emplace(state.hex, res);
m_depth.emplace(state.hex, res);
return res;
return res;
}
void StateCache::Clear()
{
for (auto it : m_depth)
{
SAFE_RELEASE(it.second);
}
m_depth.clear();
for (auto it : m_depth)
{
SAFE_RELEASE(it.second);
}
m_depth.clear();
for (auto it : m_raster)
{
SAFE_RELEASE(it.second);
}
m_raster.clear();
for (auto it : m_raster)
{
SAFE_RELEASE(it.second);
}
m_raster.clear();
for (auto it : m_blend)
{
SAFE_RELEASE(it.second);
}
m_blend.clear();
for (auto it : m_blend)
{
SAFE_RELEASE(it.second);
}
m_blend.clear();
for (auto it : m_sampler)
{
SAFE_RELEASE(it.second);
}
m_sampler.clear();
for (auto it : m_sampler)
{
SAFE_RELEASE(it.second);
}
m_sampler.clear();
}
} // namespace DX11

View File

@ -18,76 +18,69 @@ struct ID3D11RasterizerState;
namespace DX11
{
union RasterizerState {
BitField<0, 2, D3D11_CULL_MODE> cull_mode;
union RasterizerState
{
BitField<0, 2, D3D11_CULL_MODE> cull_mode;
u32 packed;
u32 packed;
};
union BlendState
{
BitField<0, 1, u32> blend_enable;
BitField<1, 3, D3D11_BLEND_OP> blend_op;
BitField<4, 4, u32> write_mask;
BitField<8, 5, D3D11_BLEND> src_blend;
BitField<13, 5, D3D11_BLEND> dst_blend;
BitField<18, 1, u32> use_dst_alpha;
union BlendState {
BitField<0, 1, u32> blend_enable;
BitField<1, 3, D3D11_BLEND_OP> blend_op;
BitField<4, 4, u32> write_mask;
BitField<8, 5, D3D11_BLEND> src_blend;
BitField<13, 5, D3D11_BLEND> dst_blend;
BitField<18, 1, u32> use_dst_alpha;
u32 packed;
u32 packed;
};
union SamplerState
{
BitField<0, 3, u64> min_filter;
BitField<3, 1, u64> mag_filter;
BitField<4, 8, u64> min_lod;
BitField<12, 8, u64> max_lod;
BitField<20, 8, s64> lod_bias;
BitField<28, 2, u64> wrap_s;
BitField<30, 2, u64> wrap_t;
BitField<32, 5, u64> max_anisotropy;
union SamplerState {
BitField<0, 3, u64> min_filter;
BitField<3, 1, u64> mag_filter;
BitField<4, 8, u64> min_lod;
BitField<12, 8, u64> max_lod;
BitField<20, 8, s64> lod_bias;
BitField<28, 2, u64> wrap_s;
BitField<30, 2, u64> wrap_t;
BitField<32, 5, u64> max_anisotropy;
u64 packed;
u64 packed;
};
class StateCache
{
public:
// Get existing or create new render state.
// Returned objects is owned by the cache and does not need to be released.
ID3D11SamplerState* Get(SamplerState state);
ID3D11BlendState* Get(BlendState state);
ID3D11RasterizerState* Get(RasterizerState state);
ID3D11DepthStencilState* Get(ZMode state);
// Get existing or create new render state.
// Returned objects is owned by the cache and does not need to be released.
ID3D11SamplerState* Get(SamplerState state);
ID3D11BlendState* Get(BlendState state);
ID3D11RasterizerState* Get(RasterizerState state);
ID3D11DepthStencilState* Get(ZMode state);
// Release all cached states and clear hash tables.
void Clear();
// Release all cached states and clear hash tables.
void Clear();
private:
std::unordered_map<u32, ID3D11DepthStencilState*> m_depth;
std::unordered_map<u32, ID3D11RasterizerState*> m_raster;
std::unordered_map<u32, ID3D11BlendState*> m_blend;
std::unordered_map<u64, ID3D11SamplerState*> m_sampler;
std::unordered_map<u32, ID3D11DepthStencilState*> m_depth;
std::unordered_map<u32, ID3D11RasterizerState*> m_raster;
std::unordered_map<u32, ID3D11BlendState*> m_blend;
std::unordered_map<u64, ID3D11SamplerState*> m_sampler;
};
namespace D3D
{
template<typename T> class AutoState
template <typename T>
class AutoState
{
public:
AutoState(const T* object);
AutoState(const AutoState<T> &source);
~AutoState();
const inline T* GetPtr() const { return state; }
AutoState(const T* object);
AutoState(const AutoState<T>& source);
~AutoState();
const inline T* GetPtr() const { return state; }
private:
const T* state;
const T* state;
};
typedef AutoState<ID3D11BlendState> AutoBlendState;
@ -97,199 +90,199 @@ typedef AutoState<ID3D11RasterizerState> AutoRasterizerState;
class StateManager
{
public:
StateManager();
StateManager();
// call any of these to change the affected states
void PushBlendState(const ID3D11BlendState* state);
void PushDepthState(const ID3D11DepthStencilState* state);
void PushRasterizerState(const ID3D11RasterizerState* state);
// call any of these to change the affected states
void PushBlendState(const ID3D11BlendState* state);
void PushDepthState(const ID3D11DepthStencilState* state);
void PushRasterizerState(const ID3D11RasterizerState* state);
// call these after drawing
void PopBlendState();
void PopDepthState();
void PopRasterizerState();
// call these after drawing
void PopBlendState();
void PopDepthState();
void PopRasterizerState();
void SetTexture(u32 index, ID3D11ShaderResourceView* texture)
{
if (m_current.textures[index] != texture)
m_dirtyFlags |= DirtyFlag_Texture0 << index;
void SetTexture(u32 index, ID3D11ShaderResourceView* texture)
{
if (m_current.textures[index] != texture)
m_dirtyFlags |= DirtyFlag_Texture0 << index;
m_pending.textures[index] = texture;
}
m_pending.textures[index] = texture;
}
void SetSampler(u32 index, ID3D11SamplerState* sampler)
{
if (m_current.samplers[index] != sampler)
m_dirtyFlags |= DirtyFlag_Sampler0 << index;
void SetSampler(u32 index, ID3D11SamplerState* sampler)
{
if (m_current.samplers[index] != sampler)
m_dirtyFlags |= DirtyFlag_Sampler0 << index;
m_pending.samplers[index] = sampler;
}
m_pending.samplers[index] = sampler;
}
void SetPixelConstants(ID3D11Buffer* buffer0, ID3D11Buffer* buffer1 = nullptr)
{
if (m_current.pixelConstants[0] != buffer0 || m_current.pixelConstants[1] != buffer1)
m_dirtyFlags |= DirtyFlag_PixelConstants;
void SetPixelConstants(ID3D11Buffer* buffer0, ID3D11Buffer* buffer1 = nullptr)
{
if (m_current.pixelConstants[0] != buffer0 || m_current.pixelConstants[1] != buffer1)
m_dirtyFlags |= DirtyFlag_PixelConstants;
m_pending.pixelConstants[0] = buffer0;
m_pending.pixelConstants[1] = buffer1;
}
m_pending.pixelConstants[0] = buffer0;
m_pending.pixelConstants[1] = buffer1;
}
void SetVertexConstants(ID3D11Buffer* buffer)
{
if (m_current.vertexConstants != buffer)
m_dirtyFlags |= DirtyFlag_VertexConstants;
void SetVertexConstants(ID3D11Buffer* buffer)
{
if (m_current.vertexConstants != buffer)
m_dirtyFlags |= DirtyFlag_VertexConstants;
m_pending.vertexConstants = buffer;
}
m_pending.vertexConstants = buffer;
}
void SetGeometryConstants(ID3D11Buffer* buffer)
{
if (m_current.geometryConstants != buffer)
m_dirtyFlags |= DirtyFlag_GeometryConstants;
void SetGeometryConstants(ID3D11Buffer* buffer)
{
if (m_current.geometryConstants != buffer)
m_dirtyFlags |= DirtyFlag_GeometryConstants;
m_pending.geometryConstants = buffer;
}
m_pending.geometryConstants = buffer;
}
void SetVertexBuffer(ID3D11Buffer* buffer, u32 stride, u32 offset)
{
if (m_current.vertexBuffer != buffer ||
m_current.vertexBufferStride != stride ||
m_current.vertexBufferOffset != offset)
m_dirtyFlags |= DirtyFlag_VertexBuffer;
void SetVertexBuffer(ID3D11Buffer* buffer, u32 stride, u32 offset)
{
if (m_current.vertexBuffer != buffer || m_current.vertexBufferStride != stride ||
m_current.vertexBufferOffset != offset)
m_dirtyFlags |= DirtyFlag_VertexBuffer;
m_pending.vertexBuffer = buffer;
m_pending.vertexBufferStride = stride;
m_pending.vertexBufferOffset = offset;
}
m_pending.vertexBuffer = buffer;
m_pending.vertexBufferStride = stride;
m_pending.vertexBufferOffset = offset;
}
void SetIndexBuffer(ID3D11Buffer* buffer)
{
if (m_current.indexBuffer != buffer)
m_dirtyFlags |= DirtyFlag_IndexBuffer;
void SetIndexBuffer(ID3D11Buffer* buffer)
{
if (m_current.indexBuffer != buffer)
m_dirtyFlags |= DirtyFlag_IndexBuffer;
m_pending.indexBuffer = buffer;
}
m_pending.indexBuffer = buffer;
}
void SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology)
{
if (m_current.topology != topology)
m_dirtyFlags |= DirtyFlag_InputAssembler;
void SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology)
{
if (m_current.topology != topology)
m_dirtyFlags |= DirtyFlag_InputAssembler;
m_pending.topology = topology;
}
m_pending.topology = topology;
}
void SetInputLayout(ID3D11InputLayout* layout)
{
if (m_current.inputLayout != layout)
m_dirtyFlags |= DirtyFlag_InputAssembler;
void SetInputLayout(ID3D11InputLayout* layout)
{
if (m_current.inputLayout != layout)
m_dirtyFlags |= DirtyFlag_InputAssembler;
m_pending.inputLayout = layout;
}
m_pending.inputLayout = layout;
}
void SetPixelShader(ID3D11PixelShader* shader)
{
if (m_current.pixelShader != shader)
m_dirtyFlags |= DirtyFlag_PixelShader;
void SetPixelShader(ID3D11PixelShader* shader)
{
if (m_current.pixelShader != shader)
m_dirtyFlags |= DirtyFlag_PixelShader;
m_pending.pixelShader = shader;
}
m_pending.pixelShader = shader;
}
void SetPixelShaderDynamic(ID3D11PixelShader* shader, ID3D11ClassInstance * const * classInstances, u32 classInstancesCount)
{
D3D::context->PSSetShader(shader, classInstances, classInstancesCount);
m_current.pixelShader = shader;
m_pending.pixelShader = shader;
}
void SetPixelShaderDynamic(ID3D11PixelShader* shader, ID3D11ClassInstance* const* classInstances,
u32 classInstancesCount)
{
D3D::context->PSSetShader(shader, classInstances, classInstancesCount);
m_current.pixelShader = shader;
m_pending.pixelShader = shader;
}
void SetVertexShader(ID3D11VertexShader* shader)
{
if (m_current.vertexShader != shader)
m_dirtyFlags |= DirtyFlag_VertexShader;
void SetVertexShader(ID3D11VertexShader* shader)
{
if (m_current.vertexShader != shader)
m_dirtyFlags |= DirtyFlag_VertexShader;
m_pending.vertexShader = shader;
}
m_pending.vertexShader = shader;
}
void SetGeometryShader(ID3D11GeometryShader* shader)
{
if (m_current.geometryShader != shader)
m_dirtyFlags |= DirtyFlag_GeometryShader;
void SetGeometryShader(ID3D11GeometryShader* shader)
{
if (m_current.geometryShader != shader)
m_dirtyFlags |= DirtyFlag_GeometryShader;
m_pending.geometryShader = shader;
}
m_pending.geometryShader = shader;
}
// removes currently set texture from all slots, returns mask of previously bound slots
u32 UnsetTexture(ID3D11ShaderResourceView* srv);
void SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv);
// removes currently set texture from all slots, returns mask of previously bound slots
u32 UnsetTexture(ID3D11ShaderResourceView* srv);
void SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv);
// call this immediately before any drawing operation or to explicitly apply pending resource state changes
void Apply();
// call this immediately before any drawing operation or to explicitly apply pending resource
// state changes
void Apply();
private:
std::stack<AutoBlendState> m_blendStates;
std::stack<AutoDepthStencilState> m_depthStates;
std::stack<AutoRasterizerState> m_rasterizerStates;
std::stack<AutoBlendState> m_blendStates;
std::stack<AutoDepthStencilState> m_depthStates;
std::stack<AutoRasterizerState> m_rasterizerStates;
ID3D11BlendState* m_currentBlendState;
ID3D11DepthStencilState* m_currentDepthState;
ID3D11RasterizerState* m_currentRasterizerState;
ID3D11BlendState* m_currentBlendState;
ID3D11DepthStencilState* m_currentDepthState;
ID3D11RasterizerState* m_currentRasterizerState;
enum DirtyFlags
{
DirtyFlag_Texture0 = 1 << 0,
DirtyFlag_Texture1 = 1 << 1,
DirtyFlag_Texture2 = 1 << 2,
DirtyFlag_Texture3 = 1 << 3,
DirtyFlag_Texture4 = 1 << 4,
DirtyFlag_Texture5 = 1 << 5,
DirtyFlag_Texture6 = 1 << 6,
DirtyFlag_Texture7 = 1 << 7,
enum DirtyFlags
{
DirtyFlag_Texture0 = 1 << 0,
DirtyFlag_Texture1 = 1 << 1,
DirtyFlag_Texture2 = 1 << 2,
DirtyFlag_Texture3 = 1 << 3,
DirtyFlag_Texture4 = 1 << 4,
DirtyFlag_Texture5 = 1 << 5,
DirtyFlag_Texture6 = 1 << 6,
DirtyFlag_Texture7 = 1 << 7,
DirtyFlag_Sampler0 = 1 << 8,
DirtyFlag_Sampler1 = 1 << 9,
DirtyFlag_Sampler2 = 1 << 10,
DirtyFlag_Sampler3 = 1 << 11,
DirtyFlag_Sampler4 = 1 << 12,
DirtyFlag_Sampler5 = 1 << 13,
DirtyFlag_Sampler6 = 1 << 14,
DirtyFlag_Sampler7 = 1 << 15,
DirtyFlag_Sampler0 = 1 << 8,
DirtyFlag_Sampler1 = 1 << 9,
DirtyFlag_Sampler2 = 1 << 10,
DirtyFlag_Sampler3 = 1 << 11,
DirtyFlag_Sampler4 = 1 << 12,
DirtyFlag_Sampler5 = 1 << 13,
DirtyFlag_Sampler6 = 1 << 14,
DirtyFlag_Sampler7 = 1 << 15,
DirtyFlag_PixelConstants = 1 << 16,
DirtyFlag_VertexConstants = 1 << 17,
DirtyFlag_GeometryConstants = 1 << 18,
DirtyFlag_PixelConstants = 1 << 16,
DirtyFlag_VertexConstants = 1 << 17,
DirtyFlag_GeometryConstants = 1 << 18,
DirtyFlag_VertexBuffer = 1 << 19,
DirtyFlag_IndexBuffer = 1 << 20,
DirtyFlag_VertexBuffer = 1 << 19,
DirtyFlag_IndexBuffer = 1 << 20,
DirtyFlag_PixelShader = 1 << 21,
DirtyFlag_VertexShader = 1 << 22,
DirtyFlag_GeometryShader = 1 << 23,
DirtyFlag_PixelShader = 1 << 21,
DirtyFlag_VertexShader = 1 << 22,
DirtyFlag_GeometryShader = 1 << 23,
DirtyFlag_InputAssembler = 1 << 24,
};
DirtyFlag_InputAssembler = 1 << 24,
};
u32 m_dirtyFlags;
u32 m_dirtyFlags;
struct Resources
{
ID3D11ShaderResourceView* textures[8];
ID3D11SamplerState* samplers[8];
ID3D11Buffer* pixelConstants[2];
ID3D11Buffer* vertexConstants;
ID3D11Buffer* geometryConstants;
ID3D11Buffer* vertexBuffer;
ID3D11Buffer* indexBuffer;
u32 vertexBufferStride;
u32 vertexBufferOffset;
D3D11_PRIMITIVE_TOPOLOGY topology;
ID3D11InputLayout* inputLayout;
ID3D11PixelShader* pixelShader;
ID3D11VertexShader* vertexShader;
ID3D11GeometryShader* geometryShader;
};
struct Resources
{
ID3D11ShaderResourceView* textures[8];
ID3D11SamplerState* samplers[8];
ID3D11Buffer* pixelConstants[2];
ID3D11Buffer* vertexConstants;
ID3D11Buffer* geometryConstants;
ID3D11Buffer* vertexBuffer;
ID3D11Buffer* indexBuffer;
u32 vertexBufferStride;
u32 vertexBufferOffset;
D3D11_PRIMITIVE_TOPOLOGY topology;
ID3D11InputLayout* inputLayout;
ID3D11PixelShader* pixelShader;
ID3D11VertexShader* vertexShader;
ID3D11GeometryShader* geometryShader;
};
Resources m_pending;
Resources m_current;
Resources m_pending;
Resources m_current;
};
extern StateManager* stateman;

View File

@ -11,110 +11,129 @@
namespace DX11
{
namespace D3D
{
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int src_pitch, unsigned int level, D3D11_USAGE usage)
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width,
unsigned int height, unsigned int src_pitch, unsigned int level,
D3D11_USAGE usage)
{
if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (src_pitch == map.RowPitch)
{
memcpy(map.pData, buffer, map.RowPitch * height);
}
else
{
// Source row size is aligned to texture block size. This can result in a different
// pitch to what the driver returns, so copy whichever is smaller.
unsigned int copy_size = std::min(src_pitch, map.RowPitch);
for (unsigned int y = 0; y < height; ++y)
memcpy((u8*)map.pData + y * map.RowPitch, buffer + y * src_pitch, copy_size);
}
D3D::context->Unmap(pTexture, level);
}
else
{
D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1);
D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, src_pitch, src_pitch * height);
}
if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (src_pitch == map.RowPitch)
{
memcpy(map.pData, buffer, map.RowPitch * height);
}
else
{
// Source row size is aligned to texture block size. This can result in a different
// pitch to what the driver returns, so copy whichever is smaller.
unsigned int copy_size = std::min(src_pitch, map.RowPitch);
for (unsigned int y = 0; y < height; ++y)
memcpy((u8*)map.pData + y * map.RowPitch, buffer + y * src_pitch, copy_size);
}
D3D::context->Unmap(pTexture, level);
}
else
{
D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1);
D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, src_pitch,
src_pitch * height);
}
}
} // namespace
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)
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;
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;
}
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;
D3DTexture2D* ret = new D3DTexture2D(pTexture, bind);
SAFE_RELEASE(pTexture);
return ret;
}
void D3DTexture2D::AddRef()
{
++ref;
++ref;
}
UINT D3DTexture2D::Release()
{
--ref;
if (ref == 0)
{
delete this;
return 0;
}
return ref;
--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)
: ref(1), tex(texptr), srv(nullptr), rtv(nullptr), dsv(nullptr)
ID3D11Texture2D*& D3DTexture2D::GetTex()
{
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();
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)
: ref(1), tex(texptr), srv(nullptr), rtv(nullptr), dsv(nullptr)
{
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);
SAFE_RELEASE(srv);
SAFE_RELEASE(rtv);
SAFE_RELEASE(dsv);
SAFE_RELEASE(tex);
}
} // namespace DX11

View File

@ -8,40 +8,48 @@
namespace DX11
{
namespace D3D
{
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int src_pitch, unsigned int level, D3D11_USAGE usage);
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width,
unsigned int height, unsigned int src_pitch, unsigned int level,
D3D11_USAGE usage);
}
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
// 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);
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();
// 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();
ID3D11Texture2D*& GetTex();
ID3D11ShaderResourceView*& GetSRV();
ID3D11RenderTargetView*& GetRTV();
ID3D11DepthStencilView*& GetDSV();
private:
~D3DTexture2D();
~D3DTexture2D();
ID3D11Texture2D* tex;
ID3D11ShaderResourceView* srv;
ID3D11RenderTargetView* rtv;
ID3D11DepthStencilView* dsv;
D3D11_BIND_FLAG bindflags;
UINT ref;
ID3D11Texture2D* tex;
ID3D11ShaderResourceView* srv;
ID3D11RenderTargetView* rtv;
ID3D11DepthStencilView* dsv;
D3D11_BIND_FLAG bindflags;
UINT ref;
};
} // namespace DX11

File diff suppressed because it is too large Load Diff

View File

@ -12,64 +12,54 @@
namespace DX11
{
namespace D3D
{
// Font creation flags
#define D3DFONT_BOLD 0x0001
#define D3DFONT_ITALIC 0x0002
// Font creation flags
#define D3DFONT_BOLD 0x0001
#define D3DFONT_ITALIC 0x0002
// Font rendering flags
#define D3DFONT_CENTERED 0x0001
// Font rendering flags
#define D3DFONT_CENTERED 0x0001
class CD3DFont
{
ID3D11ShaderResourceView* m_pTexture;
ID3D11Buffer* m_pVB;
ID3D11InputLayout* m_InputLayout;
ID3D11PixelShader* m_pshader;
ID3D11VertexShader* m_vshader;
ID3D11BlendState* m_blendstate;
ID3D11RasterizerState* m_raststate;
const int m_dwTexWidth;
const int m_dwTexHeight;
unsigned int m_LineHeight;
float m_fTexCoords[128-32][4];
class CD3DFont
{
ID3D11ShaderResourceView* m_pTexture;
ID3D11Buffer* m_pVB;
ID3D11InputLayout* m_InputLayout;
ID3D11PixelShader* m_pshader;
ID3D11VertexShader* m_vshader;
ID3D11BlendState* m_blendstate;
ID3D11RasterizerState* m_raststate;
const int m_dwTexWidth;
const int m_dwTexHeight;
unsigned int m_LineHeight;
float m_fTexCoords[128 - 32][4];
public:
CD3DFont();
// 2D text drawing function
// Initializing and destroying device-dependent objects
int Init();
int Shutdown();
int DrawTextScaled(float x, float y,
float size,
float spacing, u32 dwColor,
const std::string& text);
};
public:
CD3DFont();
// 2D text drawing function
// Initializing and destroying device-dependent objects
int Init();
int Shutdown();
int DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor,
const std::string& text);
};
extern CD3DFont font;
extern CD3DFont font;
void InitUtils();
void ShutdownUtils();
void InitUtils();
void ShutdownUtils();
void SetPointCopySampler();
void SetLinearCopySampler();
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,
float Gamma = 1.0f,
u32 slice = 0);
void drawClearQuad(u32 Color, float z);
void drawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2);
void drawShadedTexQuad(ID3D11ShaderResourceView* texture, const D3D11_RECT* rSource,
int SourceWidth, int SourceHeight, ID3D11PixelShader* PShader,
ID3D11VertexShader* VShader, ID3D11InputLayout* layout,
ID3D11GeometryShader* GShader = nullptr, float Gamma = 1.0f, 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);
void DrawEFBPokeQuads(EFBAccessType type, const EfbPokeData* points, size_t num_points);
}
}

View File

@ -18,235 +18,312 @@
namespace DX11
{
static XFBEncoder s_xfbEncoder;
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()
D3DTexture2D*& FramebufferManager::GetEFBColorTexture()
{
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;
}
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::GetResolvedEFBDepthTexture()
D3DTexture2D*& FramebufferManager::GetEFBDepthTexture()
{
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();
return m_efb.depth_tex;
}
D3DTexture2D*& FramebufferManager::GetEFBDepthReadTexture()
{
return m_efb.depth_read_texture;
}
ID3D11Texture2D*& FramebufferManager::GetEFBDepthStagingBuffer()
{
return m_efb.depth_staging_buf;
}
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);
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;
}
}
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());
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();
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
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);
return m_efb.resolved_depth_tex;
}
else
{
return m_efb.depth_tex;
}
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());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
return m_efb.resolved_depth_tex;
}
else
{
return m_efb.depth_tex;
}
}
FramebufferManager::FramebufferManager()
{
m_target_width = Renderer::GetTargetWidth();
m_target_height = Renderer::GetTargetHeight();
if (m_target_height < 1)
{
m_target_height = 1;
}
if (m_target_width < 1)
{
m_target_width = 1;
}
DXGI_SAMPLE_DESC sample_desc;
sample_desc.Count = g_ActiveConfig.iMultisamples;
sample_desc.Quality = 0;
m_target_width = Renderer::GetTargetWidth();
m_target_height = Renderer::GetTargetHeight();
if (m_target_height < 1)
{
m_target_height = 1;
}
if (m_target_width < 1)
{
m_target_width = 1;
}
DXGI_SAMPLE_DESC sample_desc;
sample_desc.Count = g_ActiveConfig.iMultisamples;
sample_desc.Quality = 0;
ID3D11Texture2D* buf;
D3D11_TEXTURE2D_DESC texdesc;
HRESULT hr;
ID3D11Texture2D* buf;
D3D11_TEXTURE2D_DESC texdesc;
HRESULT hr;
m_EFBLayers = m_efb.slices = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1;
m_EFBLayers = m_efb.slices = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1;
// EFB color texture - primary render target
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 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((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(), "EFB color texture shader resource view");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(), "EFB color texture render target view");
// EFB color texture - primary render target
texdesc =
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 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((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(),
"EFB color texture shader resource view");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(),
"EFB color texture render target view");
// Temporary EFB color texture - used in ReinterpretPixelData
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 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((ID3D11DeviceChild*)m_efb.color_temp_tex->GetTex(), "EFB color temp texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetSRV(), "EFB color temp texture shader resource view");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetRTV(), "EFB color temp texture render target view");
// Temporary EFB color texture - used in ReinterpretPixelData
texdesc =
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 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((ID3D11DeviceChild*)m_efb.color_temp_tex->GetTex(),
"EFB color temp texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetSRV(),
"EFB color temp texture shader resource view");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetRTV(),
"EFB color temp texture render target view");
// 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((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), "EFB color read texture (used in Renderer::AccessEFB)");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), "EFB color read texture render target view (used in Renderer::AccessEFB)");
// 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((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(),
"EFB color read texture (used in Renderer::AccessEFB)");
D3D::SetDebugObjectName(
(ID3D11DeviceChild*)m_efb.depth_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((ID3D11DeviceChild*)m_efb.color_staging_buf, "EFB color staging texture (used for 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((ID3D11DeviceChild*)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((ID3D11DeviceChild*)m_efb.depth_tex->GetTex(), "EFB depth texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view");
// 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((ID3D11DeviceChild*)m_efb.depth_tex->GetTex(), "EFB depth texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetDSV(),
"EFB depth texture depth stencil view");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetSRV(),
"EFB depth texture shader resource view");
// 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((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), "EFB depth read texture (used in Renderer::AccessEFB)");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), "EFB depth read texture render target view (used in Renderer::AccessEFB)");
// 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((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(),
"EFB depth read texture (used in Renderer::AccessEFB)");
D3D::SetDebugObjectName(
(ID3D11DeviceChild*)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((ID3D11DeviceChild*)m_efb.depth_staging_buf, "EFB depth staging texture (used for 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((ID3D11DeviceChild*)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((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetTex(), "EFB color resolve texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetSRV(), "EFB color resolve texture shader resource view");
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((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetTex(),
"EFB color resolve texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)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((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetTex(), "EFB depth resolve texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)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;
}
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((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetTex(),
"EFB depth resolve texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)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_xfbEncoder.Init();
s_xfbEncoder.Init();
}
FramebufferManager::~FramebufferManager()
{
s_xfbEncoder.Shutdown();
s_xfbEncoder.Shutdown();
SAFE_RELEASE(m_efb.color_tex);
SAFE_RELEASE(m_efb.color_temp_tex);
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);
SAFE_RELEASE(m_efb.color_tex);
SAFE_RELEASE(m_efb.color_temp_tex);
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);
}
void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma)
void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight,
const EFBRectangle& sourceRc, float Gamma)
{
u8* dst = Memory::GetPointer(xfbAddr);
// below div2 due to dx using pixel width
s_xfbEncoder.Encode(dst, fbStride/2, fbHeight, sourceRc, Gamma);
u8* dst = Memory::GetPointer(xfbAddr);
// below div2 due to dx using pixel width
s_xfbEncoder.Encode(dst, fbStride / 2, fbHeight, sourceRc, Gamma);
}
std::unique_ptr<XFBSourceBase> FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers)
std::unique_ptr<XFBSourceBase> FramebufferManager::CreateXFBSource(unsigned int target_width,
unsigned int target_height,
unsigned int layers)
{
return std::make_unique<XFBSource>(D3DTexture2D::Create(target_width, target_height,
(D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE),
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers), layers);
return std::make_unique<XFBSource>(
D3DTexture2D::Create(target_width, target_height,
(D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE),
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers),
layers);
}
void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height)
void FramebufferManager::GetTargetSize(unsigned int* width, unsigned int* height)
{
*width = m_target_width;
*height = m_target_height;
*width = m_target_width;
*height = m_target_height;
}
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
{
// DX11's XFB decoder does not use this function.
// YUYV data is decoded in Render::Swap.
// DX11's XFB decoder does not use this function.
// YUYV data is decoded in Render::Swap.
}
void XFBSource::CopyEFB(float Gamma)
{
g_renderer->ResetAPIState(); // reset any game specific settings
g_renderer->ResetAPIState(); // reset any game specific settings
// Copy EFB data to XFB and restore render target again
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight);
const D3D11_RECT rect = CD3D11_RECT(0, 0, texWidth, texHeight);
// Copy EFB data to XFB and restore render target again
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight);
const D3D11_RECT rect = CD3D11_RECT(0, 0, texWidth, texHeight);
D3D::context->RSSetViewports(1, &vp);
D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), nullptr);
D3D::SetPointCopySampler();
D3D::context->RSSetViewports(1, &vp);
D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), nullptr);
D3D::SetPointCopySampler();
D3D::drawShadedTexQuad(FramebufferManager::GetEFBColorTexture()->GetSRV(), &rect,
Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(true),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader(), Gamma);
D3D::drawShadedTexQuad(
FramebufferManager::GetEFBColorTexture()->GetSRV(), &rect, Renderer::GetTargetWidth(),
Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(true),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader(), Gamma);
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
g_renderer->RestoreAPIState();
}
} // namespace DX11

View File

@ -46,67 +46,69 @@ namespace DX11
struct XFBSource : public XFBSourceBase
{
XFBSource(D3DTexture2D *_tex, int slices) : tex(_tex), m_slices(slices) {}
~XFBSource() { tex->Release(); }
XFBSource(D3DTexture2D* _tex, int slices) : tex(_tex), m_slices(slices) {}
~XFBSource() { tex->Release(); }
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override;
void CopyEFB(float Gamma) override;
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override;
void CopyEFB(float Gamma) override;
D3DTexture2D* const tex;
const int m_slices;
D3DTexture2D* const tex;
const int m_slices;
};
class FramebufferManager : public FramebufferManagerBase
{
public:
FramebufferManager();
~FramebufferManager();
FramebufferManager();
~FramebufferManager();
static D3DTexture2D* &GetEFBColorTexture();
static D3DTexture2D* &GetEFBColorReadTexture();
static ID3D11Texture2D* &GetEFBColorStagingBuffer();
static D3DTexture2D*& GetEFBColorTexture();
static D3DTexture2D*& GetEFBColorReadTexture();
static ID3D11Texture2D*& GetEFBColorStagingBuffer();
static D3DTexture2D* &GetEFBDepthTexture();
static D3DTexture2D* &GetEFBDepthReadTexture();
static ID3D11Texture2D* &GetEFBDepthStagingBuffer();
static D3DTexture2D*& GetEFBDepthTexture();
static D3DTexture2D*& GetEFBDepthReadTexture();
static ID3D11Texture2D*& GetEFBDepthStagingBuffer();
static D3DTexture2D* &GetResolvedEFBColorTexture();
static D3DTexture2D* &GetResolvedEFBDepthTexture();
static D3DTexture2D*& GetResolvedEFBColorTexture();
static D3DTexture2D*& GetResolvedEFBDepthTexture();
static D3DTexture2D* &GetEFBColorTempTexture() { return m_efb.color_temp_tex; }
static void SwapReinterpretTexture()
{
D3DTexture2D* swaptex = GetEFBColorTempTexture();
m_efb.color_temp_tex = GetEFBColorTexture();
m_efb.color_tex = swaptex;
}
static D3DTexture2D*& GetEFBColorTempTexture() { return m_efb.color_temp_tex; }
static void SwapReinterpretTexture()
{
D3DTexture2D* swaptex = GetEFBColorTempTexture();
m_efb.color_temp_tex = GetEFBColorTexture();
m_efb.color_tex = swaptex;
}
private:
std::unique_ptr<XFBSourceBase> CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) override;
void GetTargetSize(unsigned int *width, unsigned int *height) override;
std::unique_ptr<XFBSourceBase> CreateXFBSource(unsigned int target_width,
unsigned int target_height,
unsigned int layers) override;
void GetTargetSize(unsigned int* width, unsigned int* height) override;
void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma) override;
void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,
float Gamma) override;
static struct Efb
{
D3DTexture2D* color_tex;
ID3D11Texture2D* color_staging_buf;
D3DTexture2D* color_read_texture;
static struct Efb
{
D3DTexture2D* color_tex;
ID3D11Texture2D* color_staging_buf;
D3DTexture2D* color_read_texture;
D3DTexture2D* depth_tex;
ID3D11Texture2D* depth_staging_buf;
D3DTexture2D* depth_read_texture;
D3DTexture2D* depth_tex;
ID3D11Texture2D* depth_staging_buf;
D3DTexture2D* depth_read_texture;
D3DTexture2D* color_temp_tex;
D3DTexture2D* color_temp_tex;
D3DTexture2D* resolved_color_tex;
D3DTexture2D* resolved_depth_tex;
D3DTexture2D* resolved_color_tex;
D3DTexture2D* resolved_depth_tex;
int slices;
} m_efb;
int slices;
} m_efb;
static unsigned int m_target_width;
static unsigned int m_target_height;
static unsigned int m_target_width;
static unsigned int m_target_height;
};
} // namespace DX11

View File

@ -23,11 +23,10 @@
namespace DX11
{
GeometryShaderCache::GSCache GeometryShaderCache::GeometryShaders;
const GeometryShaderCache::GSCacheEntry* GeometryShaderCache::last_entry;
GeometryShaderUid GeometryShaderCache::last_uid;
UidChecker<GeometryShaderUid,ShaderCode> GeometryShaderCache::geometry_uid_checker;
UidChecker<GeometryShaderUid, ShaderCode> GeometryShaderCache::geometry_uid_checker;
const GeometryShaderCache::GSCacheEntry GeometryShaderCache::pass_entry;
ID3D11GeometryShader* ClearGeometryShader = nullptr;
@ -35,241 +34,250 @@ ID3D11GeometryShader* CopyGeometryShader = nullptr;
LinearDiskCache<GeometryShaderUid, u8> g_gs_disk_cache;
ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader() { return (g_ActiveConfig.iStereoMode > 0) ? ClearGeometryShader: nullptr; }
ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader() { return (g_ActiveConfig.iStereoMode > 0) ? CopyGeometryShader : nullptr; }
ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader()
{
return (g_ActiveConfig.iStereoMode > 0) ? ClearGeometryShader : nullptr;
}
ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader()
{
return (g_ActiveConfig.iStereoMode > 0) ? CopyGeometryShader : nullptr;
}
ID3D11Buffer* gscbuf = nullptr;
ID3D11Buffer* &GeometryShaderCache::GetConstantBuffer()
ID3D11Buffer*& GeometryShaderCache::GetConstantBuffer()
{
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up
if (GeometryShaderManager::dirty)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(gscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, &GeometryShaderManager::constants, sizeof(GeometryShaderConstants));
D3D::context->Unmap(gscbuf, 0);
GeometryShaderManager::dirty = false;
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to
// speed this up
if (GeometryShaderManager::dirty)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(gscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, &GeometryShaderManager::constants, sizeof(GeometryShaderConstants));
D3D::context->Unmap(gscbuf, 0);
GeometryShaderManager::dirty = false;
ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(GeometryShaderConstants));
}
return gscbuf;
ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(GeometryShaderConstants));
}
return gscbuf;
}
// this class will load the precompiled shaders into our cache
class GeometryShaderCacheInserter : public LinearDiskCacheReader<GeometryShaderUid, u8>
{
public:
void Read(const GeometryShaderUid &key, const u8* value, u32 value_size)
{
GeometryShaderCache::InsertByteCode(key, value, value_size);
}
void Read(const GeometryShaderUid& key, const u8* value, u32 value_size)
{
GeometryShaderCache::InsertByteCode(key, value, value_size);
}
};
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"
};
"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"
" float vTexCoord1 : TEXCOORD1;\n"
"};\n"
"struct GSOUTPUT\n"
"{\n"
" float4 vPosition : POSITION;\n"
" float3 vTexCoord : TEXCOORD0;\n"
" float vTexCoord1 : TEXCOORD1;\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 = slice;\n"
" OUT.vTexCoord1 = o[i].vTexCoord1;\n"
" OUT.slice = slice;\n"
" Output.Append(OUT);\n"
" }\n"
" Output.RestartStrip();\n"
"}\n"
"}\n"
};
"struct VSOUTPUT\n"
"{\n"
" float4 vPosition : POSITION;\n"
" float3 vTexCoord : TEXCOORD0;\n"
" float vTexCoord1 : TEXCOORD1;\n"
"};\n"
"struct GSOUTPUT\n"
"{\n"
" float4 vPosition : POSITION;\n"
" float3 vTexCoord : TEXCOORD0;\n"
" float vTexCoord1 : TEXCOORD1;\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 = slice;\n"
" OUT.vTexCoord1 = o[i].vTexCoord1;\n"
" OUT.slice = slice;\n"
" Output.Append(OUT);\n"
" }\n"
" Output.RestartStrip();\n"
"}\n"
"}\n"};
void GeometryShaderCache::Init()
{
unsigned int gbsize = ROUND_UP(sizeof(GeometryShaderConstants), 16); // must be a multiple of 16
D3D11_BUFFER_DESC gbdesc = CD3D11_BUFFER_DESC(gbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
HRESULT hr = D3D::device->CreateBuffer(&gbdesc, nullptr, &gscbuf);
CHECK(hr == S_OK, "Create geometry shader constant buffer (size=%u)", gbsize);
D3D::SetDebugObjectName((ID3D11DeviceChild*)gscbuf, "geometry shader constant buffer used to emulate the GX pipeline");
unsigned int gbsize = ROUND_UP(sizeof(GeometryShaderConstants), 16); // must be a multiple of 16
D3D11_BUFFER_DESC gbdesc = CD3D11_BUFFER_DESC(gbsize, D3D11_BIND_CONSTANT_BUFFER,
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
HRESULT hr = D3D::device->CreateBuffer(&gbdesc, nullptr, &gscbuf);
CHECK(hr == S_OK, "Create geometry shader constant buffer (size=%u)", gbsize);
D3D::SetDebugObjectName((ID3D11DeviceChild*)gscbuf,
"geometry shader constant buffer used to emulate the GX pipeline");
// used when drawing clear quads
ClearGeometryShader = D3D::CompileAndCreateGeometryShader(clear_shader_code);
CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearGeometryShader, "clear geometry shader");
// used when drawing clear quads
ClearGeometryShader = D3D::CompileAndCreateGeometryShader(clear_shader_code);
CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearGeometryShader, "clear geometry shader");
// used for buffer copy
CopyGeometryShader = D3D::CompileAndCreateGeometryShader(copy_shader_code);
CHECK(CopyGeometryShader != nullptr, "Create copy geometry shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)CopyGeometryShader, "copy geometry shader");
// used for buffer copy
CopyGeometryShader = D3D::CompileAndCreateGeometryShader(copy_shader_code);
CHECK(CopyGeometryShader != nullptr, "Create copy geometry shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)CopyGeometryShader, "copy geometry shader");
Clear();
Clear();
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
std::string cache_filename = StringFromFormat("%sdx11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().m_strUniqueID.c_str());
GeometryShaderCacheInserter inserter;
g_gs_disk_cache.OpenAndRead(cache_filename, inserter);
std::string cache_filename =
StringFromFormat("%sdx11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().m_strUniqueID.c_str());
GeometryShaderCacheInserter inserter;
g_gs_disk_cache.OpenAndRead(cache_filename, inserter);
if (g_Config.bEnableShaderDebugging)
Clear();
if (g_Config.bEnableShaderDebugging)
Clear();
last_entry = nullptr;
last_entry = nullptr;
}
// ONLY to be used during shutdown.
void GeometryShaderCache::Clear()
{
for (auto& iter : GeometryShaders)
iter.second.Destroy();
GeometryShaders.clear();
geometry_uid_checker.Invalidate();
for (auto& iter : GeometryShaders)
iter.second.Destroy();
GeometryShaders.clear();
geometry_uid_checker.Invalidate();
last_entry = nullptr;
last_entry = nullptr;
}
void GeometryShaderCache::Shutdown()
{
SAFE_RELEASE(gscbuf);
SAFE_RELEASE(gscbuf);
SAFE_RELEASE(ClearGeometryShader);
SAFE_RELEASE(CopyGeometryShader);
SAFE_RELEASE(ClearGeometryShader);
SAFE_RELEASE(CopyGeometryShader);
Clear();
g_gs_disk_cache.Sync();
g_gs_disk_cache.Close();
Clear();
g_gs_disk_cache.Sync();
g_gs_disk_cache.Close();
}
bool GeometryShaderCache::SetShader(u32 primitive_type)
{
GeometryShaderUid uid = GetGeometryShaderUid(primitive_type, API_D3D);
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D);
geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g");
}
GeometryShaderUid uid = GetGeometryShaderUid(primitive_type, API_D3D);
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D);
geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g");
}
// Check if the shader is already set
if (last_entry)
{
if (uid == last_uid)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true);
return true;
}
}
// Check if the shader is already set
if (last_entry)
{
if (uid == last_uid)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
return true;
}
}
last_uid = uid;
last_uid = uid;
// Check if the shader is a pass-through shader
if (uid.GetUidData()->IsPassthrough())
{
// Return the default pass-through shader
last_entry = &pass_entry;
return true;
}
// Check if the shader is a pass-through shader
if (uid.GetUidData()->IsPassthrough())
{
// Return the default pass-through shader
last_entry = &pass_entry;
return true;
}
// Check if the shader is already in the cache
GSCache::iterator iter;
iter = GeometryShaders.find(uid);
if (iter != GeometryShaders.end())
{
const GSCacheEntry &entry = iter->second;
last_entry = &entry;
// Check if the shader is already in the cache
GSCache::iterator iter;
iter = GeometryShaders.find(uid);
if (iter != GeometryShaders.end())
{
const GSCacheEntry& entry = iter->second;
last_entry = &entry;
return (entry.shader != nullptr);
}
return (entry.shader != nullptr);
}
// Need to compile a new shader
ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D);
// Need to compile a new shader
ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D);
D3DBlob* pbytecode;
if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode))
{
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return false;
}
D3DBlob* pbytecode;
if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode))
{
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return false;
}
// Insert the bytecode into the caches
g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
// Insert the bytecode into the caches
g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
pbytecode->Release();
bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
pbytecode->Release();
if (g_ActiveConfig.bEnableShaderDebugging && success)
{
GeometryShaders[uid].code = code.GetBuffer();
}
if (g_ActiveConfig.bEnableShaderDebugging && success)
{
GeometryShaders[uid].code = code.GetBuffer();
}
return success;
return success;
}
bool GeometryShaderCache::InsertByteCode(const GeometryShaderUid &uid, const void* bytecode, unsigned int bytecodelen)
bool GeometryShaderCache::InsertByteCode(const GeometryShaderUid& uid, const void* bytecode,
unsigned int bytecodelen)
{
ID3D11GeometryShader* shader = D3D::CreateGeometryShaderFromByteCode(bytecode, bytecodelen);
if (shader == nullptr)
return false;
ID3D11GeometryShader* shader = D3D::CreateGeometryShaderFromByteCode(bytecode, bytecodelen);
if (shader == nullptr)
return false;
// TODO: Somehow make the debug name a bit more specific
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of GeometryShaderCache");
// TODO: Somehow make the debug name a bit more specific
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of GeometryShaderCache");
// Make an entry in the table
GSCacheEntry newentry;
newentry.shader = shader;
GeometryShaders[uid] = newentry;
last_entry = &GeometryShaders[uid];
// Make an entry in the table
GSCacheEntry newentry;
newentry.shader = shader;
GeometryShaders[uid] = newentry;
last_entry = &GeometryShaders[uid];
if (!shader)
return false;
if (!shader)
return false;
return true;
return true;
}
} // DX11

View File

@ -11,41 +11,41 @@
namespace DX11
{
class GeometryShaderCache
{
public:
static void Init();
static void Clear();
static void Shutdown();
static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader
static bool InsertByteCode(const GeometryShaderUid &uid, const void* bytecode, unsigned int bytecodelen);
static void Init();
static void Clear();
static void Shutdown();
static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader
static bool InsertByteCode(const GeometryShaderUid& uid, const void* bytecode,
unsigned int bytecodelen);
static ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader();
static ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader();
static ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader();
static ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader();
static ID3D11GeometryShader* GetActiveShader() { return last_entry->shader; }
static ID3D11Buffer* &GetConstantBuffer();
static ID3D11GeometryShader* GetActiveShader() { return last_entry->shader; }
static ID3D11Buffer*& GetConstantBuffer();
private:
struct GSCacheEntry
{
ID3D11GeometryShader* shader;
struct GSCacheEntry
{
ID3D11GeometryShader* shader;
std::string code;
std::string code;
GSCacheEntry() : shader(nullptr) {}
void Destroy() { SAFE_RELEASE(shader); }
};
GSCacheEntry() : shader(nullptr) {}
void Destroy() { SAFE_RELEASE(shader); }
};
typedef std::map<GeometryShaderUid, GSCacheEntry> GSCache;
typedef std::map<GeometryShaderUid, GSCacheEntry> GSCache;
static GSCache GeometryShaders;
static const GSCacheEntry* last_entry;
static GeometryShaderUid last_uid;
static const GSCacheEntry pass_entry;
static GSCache GeometryShaders;
static const GSCacheEntry* last_entry;
static GeometryShaderUid last_uid;
static const GSCacheEntry pass_entry;
static UidChecker<GeometryShaderUid, ShaderCode> geometry_uid_checker;
static UidChecker<GeometryShaderUid, ShaderCode> geometry_uid_checker;
};
} // namespace DX11

View File

@ -13,134 +13,139 @@
namespace DX11
{
class D3DVertexFormat : public NativeVertexFormat
{
public:
D3DVertexFormat(const PortableVertexDeclaration& vtx_decl);
~D3DVertexFormat() { SAFE_RELEASE(m_layout); }
void SetupVertexPointers() override;
D3DVertexFormat(const PortableVertexDeclaration& vtx_decl);
~D3DVertexFormat() { SAFE_RELEASE(m_layout); }
void SetupVertexPointers() override;
private:
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
UINT m_num_elems = 0;
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
UINT m_num_elems = 0;
ID3D11InputLayout* m_layout = nullptr;
ID3D11InputLayout* m_layout = nullptr;
};
NativeVertexFormat* VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
NativeVertexFormat*
VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{
return new D3DVertexFormat(vtx_decl);
return new D3DVertexFormat(vtx_decl);
}
static const DXGI_FORMAT d3d_format_lookup[5*4*2] =
{
// float formats
DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R32_FLOAT,
DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R32G32_FLOAT,
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R32G32B32A32_FLOAT,
static const DXGI_FORMAT d3d_format_lookup[5 * 4 * 2] = {
// float formats
DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_SNORM,
DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R16G16_UNORM,
DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM,
DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R32G32B32A32_FLOAT,
// integer formats
DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN,
// integer formats
DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_SINT,
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R16G16_UINT,
DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UINT,
DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_SINT,
DXGI_FORMAT_UNKNOWN,
};
DXGI_FORMAT VarToD3D(VarType t, int size, bool integer)
{
DXGI_FORMAT retval = d3d_format_lookup[(int)t + 5*(size-1) + 5*4*(int)integer];
if (retval == DXGI_FORMAT_UNKNOWN)
{
PanicAlert("VarToD3D: Invalid type/size combo %i , %i, %i", (int)t, size, (int)integer);
}
return retval;
DXGI_FORMAT retval = d3d_format_lookup[(int)t + 5 * (size - 1) + 5 * 4 * (int)integer];
if (retval == DXGI_FORMAT_UNKNOWN)
{
PanicAlert("VarToD3D: Invalid type/size combo %i , %i, %i", (int)t, size, (int)integer);
}
return retval;
}
D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
{
this->vtx_decl = _vtx_decl;
this->vtx_decl = _vtx_decl;
const AttributeFormat* format = &_vtx_decl.position;
const AttributeFormat* format = &_vtx_decl.position;
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "POSITION";
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "POSITION";
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
for (int i = 0; i < 3; i++)
{
format = &_vtx_decl.normals[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "NORMAL";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
for (int i = 0; i < 3; i++)
{
format = &_vtx_decl.normals[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "NORMAL";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
for (int i = 0; i < 2; i++)
{
format = &_vtx_decl.colors[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "COLOR";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
for (int i = 0; i < 2; i++)
{
format = &_vtx_decl.colors[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "COLOR";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
for (int i = 0; i < 8; i++)
{
format = &_vtx_decl.texcoords[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "TEXCOORD";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
for (int i = 0; i < 8; i++)
{
format = &_vtx_decl.texcoords[i];
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "TEXCOORD";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
format = &_vtx_decl.posmtx;
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "BLENDINDICES";
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
format = &_vtx_decl.posmtx;
if (format->enable)
{
m_elems[m_num_elems].SemanticName = "BLENDINDICES";
m_elems[m_num_elems].AlignedByteOffset = format->offset;
m_elems[m_num_elems].Format = VarToD3D(format->type, format->components, format->integer);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
void D3DVertexFormat::SetupVertexPointers()
{
if (!m_layout)
{
// 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.
D3DBlob* vs_bytecode = DX11::VertexShaderCache::GetActiveShaderBytecode();
if (!m_layout)
{
// 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.
D3DBlob* vs_bytecode = DX11::VertexShaderCache::GetActiveShaderBytecode();
HRESULT hr = DX11::D3D::device->CreateInputLayout(m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout);
if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
DX11::D3D::SetDebugObjectName((ID3D11DeviceChild*)m_layout, "input layout used to emulate the GX pipeline");
}
DX11::D3D::stateman->SetInputLayout(m_layout);
HRESULT hr = DX11::D3D::device->CreateInputLayout(
m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout);
if (FAILED(hr))
PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
DX11::D3D::SetDebugObjectName((ID3D11DeviceChild*)m_layout,
"input layout used to emulate the GX pipeline");
}
DX11::D3D::stateman->SetInputLayout(m_layout);
}
} // namespace DX11
} // namespace DX11

View File

@ -2,13 +2,13 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D/PSTextureEncoder.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/FramebufferManager.h"
#include "VideoBackends/D3D/PSTextureEncoder.h"
#include "VideoBackends/D3D/Render.h"
#include "VideoBackends/D3D/TextureCache.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
@ -17,214 +17,211 @@
namespace DX11
{
struct EFBEncodeParams
{
DWORD SrcLeft;
DWORD SrcTop;
DWORD DestWidth;
DWORD ScaleFactor;
DWORD SrcLeft;
DWORD SrcTop;
DWORD DestWidth;
DWORD ScaleFactor;
};
PSTextureEncoder::PSTextureEncoder()
: m_ready(false), m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr),
m_encodeParams(nullptr)
: m_ready(false), m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr),
m_encodeParams(nullptr)
{
}
void PSTextureEncoder::Init()
{
m_ready = false;
m_ready = false;
HRESULT hr;
HRESULT hr;
// Create output texture RGBA format
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
DXGI_FORMAT_B8G8R8A8_UNORM,
EFB_WIDTH * 4, EFB_HEIGHT / 4, 1, 1, D3D11_BIND_RENDER_TARGET);
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out);
CHECK(SUCCEEDED(hr), "create efb encode output texture");
D3D::SetDebugObjectName(m_out, "efb encoder output texture");
// Create output texture RGBA format
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_B8G8R8A8_UNORM, EFB_WIDTH * 4,
EFB_HEIGHT / 4, 1, 1, D3D11_BIND_RENDER_TARGET);
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out);
CHECK(SUCCEEDED(hr), "create efb encode output texture");
D3D::SetDebugObjectName(m_out, "efb encoder output texture");
// Create output render target view
D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out,
D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_B8G8R8A8_UNORM);
hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
CHECK(SUCCEEDED(hr), "create efb encode output render target view");
D3D::SetDebugObjectName(m_outRTV, "efb encoder output rtv");
// Create output render target view
D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(
m_out, D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_B8G8R8A8_UNORM);
hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
CHECK(SUCCEEDED(hr), "create efb encode output render target view");
D3D::SetDebugObjectName(m_outRTV, "efb encoder output rtv");
// Create output staging buffer
t2dd.Usage = D3D11_USAGE_STAGING;
t2dd.BindFlags = 0;
t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage);
CHECK(SUCCEEDED(hr), "create efb encode output staging buffer");
D3D::SetDebugObjectName(m_outStage, "efb encoder output staging buffer");
// Create output staging buffer
t2dd.Usage = D3D11_USAGE_STAGING;
t2dd.BindFlags = 0;
t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage);
CHECK(SUCCEEDED(hr), "create efb encode output staging buffer");
D3D::SetDebugObjectName(m_outStage, "efb encoder output staging buffer");
// Create constant buffer for uploading data to shaders
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(EFBEncodeParams),
D3D11_BIND_CONSTANT_BUFFER);
hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams);
CHECK(SUCCEEDED(hr), "create efb encode params buffer");
D3D::SetDebugObjectName(m_encodeParams, "efb encoder params buffer");
// Create constant buffer for uploading data to shaders
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(EFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER);
hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams);
CHECK(SUCCEEDED(hr), "create efb encode params buffer");
D3D::SetDebugObjectName(m_encodeParams, "efb encoder params buffer");
m_ready = true;
m_ready = true;
}
void PSTextureEncoder::Shutdown()
{
m_ready = false;
m_ready = false;
for (auto& it : m_staticShaders)
{
SAFE_RELEASE(it.second);
}
m_staticShaders.clear();
for (auto& it : m_staticShaders)
{
SAFE_RELEASE(it.second);
}
m_staticShaders.clear();
SAFE_RELEASE(m_encodeParams);
SAFE_RELEASE(m_outStage);
SAFE_RELEASE(m_outRTV);
SAFE_RELEASE(m_out);
SAFE_RELEASE(m_encodeParams);
SAFE_RELEASE(m_outStage);
SAFE_RELEASE(m_outRTV);
SAFE_RELEASE(m_out);
}
void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf)
void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row,
u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf)
{
if (!m_ready) // Make sure we initialized OK
return;
if (!m_ready) // Make sure we initialized OK
return;
HRESULT hr;
HRESULT hr;
// Resolve MSAA targets before copying.
ID3D11ShaderResourceView* pEFB = (srcFormat == PEControl::Z24) ?
FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() :
// 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.
FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
// Resolve MSAA targets before copying.
ID3D11ShaderResourceView* pEFB =
(srcFormat == PEControl::Z24) ?
FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() :
// 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.
FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
// Reset API
g_renderer->ResetAPIState();
// Reset API
g_renderer->ResetAPIState();
// Set up all the state for EFB encoding
{
const u32 words_per_row = bytes_per_row / sizeof(u32);
// 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);
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);
constexpr EFBRectangle fullSrcRect(0, 0, EFB_WIDTH, EFB_HEIGHT);
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect);
D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr);
D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr);
EFBEncodeParams params;
params.SrcLeft = srcRect.left;
params.SrcTop = srcRect.top;
params.DestWidth = native_width;
params.ScaleFactor = scaleByHalf ? 2 : 1;
D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, &params, 0, 0);
D3D::stateman->SetPixelConstants(m_encodeParams);
EFBEncodeParams params;
params.SrcLeft = srcRect.left;
params.SrcTop = srcRect.top;
params.DestWidth = native_width;
params.ScaleFactor = scaleByHalf ? 2 : 1;
D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, &params, 0, 0);
D3D::stateman->SetPixelConstants(m_encodeParams);
// Use linear filtering if (bScaleByHalf), use point filtering otherwise
if (scaleByHalf)
D3D::SetLinearCopySampler();
else
D3D::SetPointCopySampler();
// Use linear filtering if (bScaleByHalf), use point filtering otherwise
if (scaleByHalf)
D3D::SetLinearCopySampler();
else
D3D::SetPointCopySampler();
D3D::drawShadedTexQuad(pEFB,
targetRect.AsRECT(),
Renderer::GetTargetWidth(),
Renderer::GetTargetHeight(),
SetStaticShader(format, srcFormat, isIntensity, scaleByHalf),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout());
D3D::drawShadedTexQuad(
pEFB, targetRect.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(),
SetStaticShader(format, srcFormat, isIntensity, scaleByHalf),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
// Copy to staging buffer
D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, words_per_row, num_blocks_y, 1);
D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox);
// Copy to staging buffer
D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, words_per_row, num_blocks_y, 1);
D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox);
// Transfer staging buffer to GameCube/Wii RAM
D3D11_MAPPED_SUBRESOURCE map = { 0 };
hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
CHECK(SUCCEEDED(hr), "map staging buffer (0x%x)", hr);
// Transfer staging buffer to GameCube/Wii RAM
D3D11_MAPPED_SUBRESOURCE map = {0};
hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
CHECK(SUCCEEDED(hr), "map staging buffer (0x%x)", hr);
u8* src = (u8*)map.pData;
u32 readStride = std::min(bytes_per_row, map.RowPitch);
for (unsigned int y = 0; y < num_blocks_y; ++y)
{
memcpy(dst, src, readStride);
dst += memory_stride;
src += map.RowPitch;
}
u8* src = (u8*)map.pData;
u32 readStride = std::min(bytes_per_row, map.RowPitch);
for (unsigned int y = 0; y < num_blocks_y; ++y)
{
memcpy(dst, src, readStride);
dst += memory_stride;
src += map.RowPitch;
}
D3D::context->Unmap(m_outStage, 0);
}
D3D::context->Unmap(m_outStage, 0);
}
// Restore API
g_renderer->RestoreAPIState();
D3D::context->OMSetRenderTargets(1,
&FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
// Restore API
g_renderer->RestoreAPIState();
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
}
ID3D11PixelShader* PSTextureEncoder::SetStaticShader(unsigned int dstFormat, PEControl::PixelFormat srcFormat,
bool isIntensity, bool scaleByHalf)
ID3D11PixelShader* PSTextureEncoder::SetStaticShader(unsigned int dstFormat,
PEControl::PixelFormat srcFormat,
bool isIntensity, bool scaleByHalf)
{
size_t fetchNum = static_cast<size_t>(srcFormat);
size_t scaledFetchNum = scaleByHalf ? 1 : 0;
size_t intensityNum = isIntensity ? 1 : 0;
size_t generatorNum = dstFormat;
size_t fetchNum = static_cast<size_t>(srcFormat);
size_t scaledFetchNum = scaleByHalf ? 1 : 0;
size_t intensityNum = isIntensity ? 1 : 0;
size_t generatorNum = dstFormat;
ComboKey key = MakeComboKey(dstFormat, srcFormat, isIntensity, scaleByHalf);
ComboKey key = MakeComboKey(dstFormat, srcFormat, isIntensity, scaleByHalf);
ComboMap::iterator it = m_staticShaders.find(key);
if (it == m_staticShaders.end())
{
INFO_LOG(VIDEO, "Compiling efb encoding shader for dstFormat 0x%X, srcFormat %d, isIntensity %d, scaleByHalf %d",
dstFormat, static_cast<int>(srcFormat), isIntensity ? 1 : 0, scaleByHalf ? 1 : 0);
ComboMap::iterator it = m_staticShaders.find(key);
if (it == m_staticShaders.end())
{
INFO_LOG(VIDEO, "Compiling efb encoding shader for dstFormat 0x%X, srcFormat %d, isIntensity "
"%d, scaleByHalf %d",
dstFormat, static_cast<int>(srcFormat), isIntensity ? 1 : 0, scaleByHalf ? 1 : 0);
u32 format = dstFormat;
u32 format = dstFormat;
if (srcFormat == PEControl::Z24)
{
format |= _GX_TF_ZTF;
if (dstFormat == 11)
format = GX_TF_Z16;
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
format |= _GX_TF_CTF;
}
else
{
if (dstFormat > GX_TF_RGBA8 || (dstFormat < GX_TF_RGB565 && !isIntensity))
format |= _GX_TF_CTF;
}
if (srcFormat == PEControl::Z24)
{
format |= _GX_TF_ZTF;
if (dstFormat == 11)
format = GX_TF_Z16;
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
format |= _GX_TF_CTF;
}
else
{
if (dstFormat > GX_TF_RGBA8 || (dstFormat < GX_TF_RGB565 && !isIntensity))
format |= _GX_TF_CTF;
}
D3DBlob* bytecode = nullptr;
const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_D3D);
if (!D3D::CompilePixelShader(shader, &bytecode))
{
WARN_LOG(VIDEO, "EFB encoder shader for dstFormat 0x%X, srcFormat %d, isIntensity %d, scaleByHalf %d failed to compile",
dstFormat, static_cast<int>(srcFormat), isIntensity ? 1 : 0, scaleByHalf ? 1 : 0);
m_staticShaders[key] = nullptr;
return nullptr;
}
D3DBlob* bytecode = nullptr;
const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_D3D);
if (!D3D::CompilePixelShader(shader, &bytecode))
{
WARN_LOG(VIDEO, "EFB encoder shader for dstFormat 0x%X, srcFormat %d, isIntensity %d, "
"scaleByHalf %d failed to compile",
dstFormat, static_cast<int>(srcFormat), isIntensity ? 1 : 0, scaleByHalf ? 1 : 0);
m_staticShaders[key] = nullptr;
return nullptr;
}
ID3D11PixelShader* newShader;
HRESULT hr = D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader);
CHECK(SUCCEEDED(hr), "create efb encoder pixel shader");
ID3D11PixelShader* newShader;
HRESULT hr =
D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader);
CHECK(SUCCEEDED(hr), "create efb encoder pixel shader");
char debugName[255] = {};
sprintf_s(debugName, "efb encoder pixel shader (dst:%d, src:%d, intensity:%d, scale:%d)",
dstFormat, srcFormat, isIntensity, scaleByHalf);
D3D::SetDebugObjectName(newShader, debugName);
char debugName[255] = {};
sprintf_s(debugName, "efb encoder pixel shader (dst:%d, src:%d, intensity:%d, scale:%d)",
dstFormat, srcFormat, isIntensity, scaleByHalf);
D3D::SetDebugObjectName(newShader, debugName);
it = m_staticShaders.emplace(key, newShader).first;
bytecode->Release();
}
it = m_staticShaders.emplace(key, newShader).first;
bytecode->Release();
}
return it->second;
return it->second;
}
}

View File

@ -23,41 +23,39 @@ struct ID3D11SamplerState;
namespace DX11
{
class PSTextureEncoder : public TextureEncoder
{
public:
PSTextureEncoder();
PSTextureEncoder();
void Init();
void Shutdown();
void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf);
void Init();
void Shutdown();
void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y,
u32 memory_stride, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf);
private:
bool m_ready;
bool m_ready;
ID3D11Texture2D* m_out;
ID3D11RenderTargetView* m_outRTV;
ID3D11Texture2D* m_outStage;
ID3D11Buffer* m_encodeParams;
ID3D11Texture2D* m_out;
ID3D11RenderTargetView* m_outRTV;
ID3D11Texture2D* m_outStage;
ID3D11Buffer* m_encodeParams;
ID3D11PixelShader* SetStaticShader(unsigned int dstFormat,
PEControl::PixelFormat srcFormat, bool isIntensity, bool scaleByHalf);
ID3D11PixelShader* SetStaticShader(unsigned int dstFormat, PEControl::PixelFormat srcFormat,
bool isIntensity, bool scaleByHalf);
typedef unsigned int ComboKey; // Key for a shader combination
typedef unsigned int ComboKey; // Key for a shader combination
ComboKey MakeComboKey(unsigned int dstFormat,
PEControl::PixelFormat srcFormat, bool isIntensity, bool scaleByHalf)
{
return (dstFormat << 4) | (static_cast<int>(srcFormat) << 2) | (isIntensity ? (1<<1) : 0)
| (scaleByHalf ? (1<<0) : 0);
}
ComboKey MakeComboKey(unsigned int dstFormat, PEControl::PixelFormat srcFormat, bool isIntensity,
bool scaleByHalf)
{
return (dstFormat << 4) | (static_cast<int>(srcFormat) << 2) | (isIntensity ? (1 << 1) : 0) |
(scaleByHalf ? (1 << 0) : 0);
}
typedef std::map<ComboKey, ID3D11PixelShader*> ComboMap;
typedef std::map<ComboKey, ID3D11PixelShader*> ComboMap;
ComboMap m_staticShaders;
ComboMap m_staticShaders;
};
}

View File

@ -2,147 +2,149 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D/PerfQuery.h"
#include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/PerfQuery.h"
#include "VideoCommon/RenderBase.h"
namespace DX11 {
PerfQuery::PerfQuery()
: m_query_read_pos()
namespace DX11
{
for (ActiveQuery& entry : m_query_buffer)
{
D3D11_QUERY_DESC qdesc = CD3D11_QUERY_DESC(D3D11_QUERY_OCCLUSION, 0);
D3D::device->CreateQuery(&qdesc, &entry.query);
}
PerfQuery::PerfQuery() : m_query_read_pos()
{
for (ActiveQuery& entry : m_query_buffer)
{
D3D11_QUERY_DESC qdesc = CD3D11_QUERY_DESC(D3D11_QUERY_OCCLUSION, 0);
D3D::device->CreateQuery(&qdesc, &entry.query);
}
ResetQuery();
ResetQuery();
}
PerfQuery::~PerfQuery()
{
for (ActiveQuery& entry : m_query_buffer)
{
// TODO: EndQuery?
entry.query->Release();
}
for (ActiveQuery& entry : m_query_buffer)
{
// TODO: EndQuery?
entry.query->Release();
}
}
void PerfQuery::EnableQuery(PerfQueryGroup type)
{
// Is this sane?
if (m_query_count > m_query_buffer.size() / 2)
WeakFlush();
// Is this sane?
if (m_query_count > m_query_buffer.size() / 2)
WeakFlush();
if (m_query_buffer.size() == m_query_count)
{
// TODO
FlushOne();
ERROR_LOG(VIDEO, "Flushed query buffer early!");
}
if (m_query_buffer.size() == m_query_count)
{
// TODO
FlushOne();
ERROR_LOG(VIDEO, "Flushed query buffer early!");
}
// start query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()];
// start query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()];
D3D::context->Begin(entry.query);
entry.query_type = type;
D3D::context->Begin(entry.query);
entry.query_type = type;
++m_query_count;
}
++m_query_count;
}
}
void PerfQuery::DisableQuery(PerfQueryGroup type)
{
// stop query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count + m_query_buffer.size()-1) % m_query_buffer.size()];
D3D::context->End(entry.query);
}
// stop query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count + m_query_buffer.size() - 1) %
m_query_buffer.size()];
D3D::context->End(entry.query);
}
}
void PerfQuery::ResetQuery()
{
m_query_count = 0;
std::fill_n(m_results, ArraySize(m_results), 0);
m_query_count = 0;
std::fill_n(m_results, ArraySize(m_results), 0);
}
u32 PerfQuery::GetQueryResult(PerfQueryType type)
{
u32 result = 0;
u32 result = 0;
if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
result = m_results[PQG_ZCOMP_ZCOMPLOC];
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
result = m_results[PQG_ZCOMP];
else if (type == PQ_BLEND_INPUT)
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
else if (type == PQ_EFB_COPY_CLOCKS)
result = m_results[PQG_EFB_COPY_CLOCKS];
if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
result = m_results[PQG_ZCOMP_ZCOMPLOC];
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
result = m_results[PQG_ZCOMP];
else if (type == PQ_BLEND_INPUT)
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
else if (type == PQ_EFB_COPY_CLOCKS)
result = m_results[PQG_EFB_COPY_CLOCKS];
return result / 4;
return result / 4;
}
void PerfQuery::FlushOne()
{
auto& entry = m_query_buffer[m_query_read_pos];
auto& entry = m_query_buffer[m_query_read_pos];
UINT64 result = 0;
HRESULT hr = S_FALSE;
while (hr != S_OK)
{
// TODO: Might cause us to be stuck in an infinite loop!
hr = D3D::context->GetData(entry.query, &result, sizeof(result), 0);
}
UINT64 result = 0;
HRESULT hr = S_FALSE;
while (hr != S_OK)
{
// TODO: Might cause us to be stuck in an infinite loop!
hr = D3D::context->GetData(entry.query, &result, sizeof(result), 0);
}
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight());
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() *
EFB_HEIGHT / g_renderer->GetTargetHeight());
m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
--m_query_count;
m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
--m_query_count;
}
// TODO: could selectively flush things, but I don't think that will do much
void PerfQuery::FlushResults()
{
while (!IsFlushed())
FlushOne();
while (!IsFlushed())
FlushOne();
}
void PerfQuery::WeakFlush()
{
while (!IsFlushed())
{
auto& entry = m_query_buffer[m_query_read_pos];
while (!IsFlushed())
{
auto& entry = m_query_buffer[m_query_read_pos];
UINT64 result = 0;
HRESULT hr = D3D::context->GetData(entry.query, &result, sizeof(result), D3D11_ASYNC_GETDATA_DONOTFLUSH);
UINT64 result = 0;
HRESULT hr =
D3D::context->GetData(entry.query, &result, sizeof(result), D3D11_ASYNC_GETDATA_DONOTFLUSH);
if (hr == S_OK)
{
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight());
if (hr == S_OK)
{
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() *
EFB_HEIGHT / g_renderer->GetTargetHeight());
m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
--m_query_count;
}
else
{
break;
}
}
m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
--m_query_count;
}
else
{
break;
}
}
}
bool PerfQuery::IsFlushed() const
{
return 0 == m_query_count;
return 0 == m_query_count;
}
} // namespace
} // namespace

View File

@ -8,38 +8,38 @@
#include "VideoCommon/PerfQueryBase.h"
namespace DX11 {
namespace DX11
{
class PerfQuery : public PerfQueryBase
{
public:
PerfQuery();
~PerfQuery();
PerfQuery();
~PerfQuery();
void EnableQuery(PerfQueryGroup type) override;
void DisableQuery(PerfQueryGroup type) override;
void ResetQuery() override;
u32 GetQueryResult(PerfQueryType type) override;
void FlushResults() override;
bool IsFlushed() const override;
void EnableQuery(PerfQueryGroup type) override;
void DisableQuery(PerfQueryGroup type) override;
void ResetQuery() override;
u32 GetQueryResult(PerfQueryType type) override;
void FlushResults() override;
bool IsFlushed() const override;
private:
struct ActiveQuery
{
ID3D11Query* query;
PerfQueryGroup query_type;
};
struct ActiveQuery
{
ID3D11Query* query;
PerfQueryGroup query_type;
};
void WeakFlush();
void WeakFlush();
// Only use when non-empty
void FlushOne();
// Only use when non-empty
void FlushOne();
// when testing in SMS: 64 was too small, 128 was ok
static const int PERF_QUERY_BUFFER_SIZE = 512;
// when testing in SMS: 64 was too small, 128 was ok
static const int PERF_QUERY_BUFFER_SIZE = 512;
std::array<ActiveQuery, PERF_QUERY_BUFFER_SIZE> m_query_buffer;
int m_query_read_pos;
std::array<ActiveQuery, PERF_QUERY_BUFFER_SIZE> m_query_buffer;
int m_query_read_pos;
};
} // namespace
} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -13,48 +13,48 @@ enum DSTALPHA_MODE;
namespace DX11
{
class PixelShaderCache
{
public:
static void Init();
static void Clear();
static void Shutdown();
static bool SetShader(DSTALPHA_MODE dstAlphaMode); // TODO: Should be renamed to LoadShader
static bool InsertByteCode(const PixelShaderUid &uid, const void* bytecode, unsigned int bytecodelen);
static void Init();
static void Clear();
static void Shutdown();
static bool SetShader(DSTALPHA_MODE dstAlphaMode); // TODO: Should be renamed to LoadShader
static bool InsertByteCode(const PixelShaderUid& uid, const void* bytecode,
unsigned int bytecodelen);
static ID3D11PixelShader* GetActiveShader() { return last_entry->shader; }
static ID3D11Buffer* &GetConstantBuffer();
static ID3D11PixelShader* GetActiveShader() { return last_entry->shader; }
static ID3D11Buffer*& GetConstantBuffer();
static ID3D11PixelShader* GetColorMatrixProgram(bool multisampled);
static ID3D11PixelShader* GetColorCopyProgram(bool multisampled);
static ID3D11PixelShader* GetDepthMatrixProgram(bool multisampled);
static ID3D11PixelShader* GetClearProgram();
static ID3D11PixelShader* GetAnaglyphProgram();
static ID3D11PixelShader* GetDepthResolveProgram();
static ID3D11PixelShader* ReinterpRGBA6ToRGB8(bool multisampled);
static ID3D11PixelShader* ReinterpRGB8ToRGBA6(bool multisampled);
static ID3D11PixelShader* GetColorMatrixProgram(bool multisampled);
static ID3D11PixelShader* GetColorCopyProgram(bool multisampled);
static ID3D11PixelShader* GetDepthMatrixProgram(bool multisampled);
static ID3D11PixelShader* GetClearProgram();
static ID3D11PixelShader* GetAnaglyphProgram();
static ID3D11PixelShader* GetDepthResolveProgram();
static ID3D11PixelShader* ReinterpRGBA6ToRGB8(bool multisampled);
static ID3D11PixelShader* ReinterpRGB8ToRGBA6(bool multisampled);
static void InvalidateMSAAShaders();
static void InvalidateMSAAShaders();
private:
struct PSCacheEntry
{
ID3D11PixelShader* shader;
struct PSCacheEntry
{
ID3D11PixelShader* shader;
std::string code;
std::string code;
PSCacheEntry() : shader(nullptr) {}
void Destroy() { SAFE_RELEASE(shader); }
};
PSCacheEntry() : shader(nullptr) {}
void Destroy() { SAFE_RELEASE(shader); }
};
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
static PSCache PixelShaders;
static const PSCacheEntry* last_entry;
static PixelShaderUid last_uid;
static PSCache PixelShaders;
static const PSCacheEntry* last_entry;
static PixelShaderUid last_uid;
static UidChecker<PixelShaderUid, ShaderCode> pixel_uid_checker;
static UidChecker<PixelShaderUid, ShaderCode> pixel_uid_checker;
};
} // namespace DX11

File diff suppressed because it is too large Load Diff

View File

@ -9,58 +9,59 @@
namespace DX11
{
class Renderer : public ::Renderer
{
public:
Renderer(void *&window_handle);
~Renderer();
Renderer(void*& window_handle);
~Renderer();
void SetColorMask() override;
void SetBlendMode(bool forceUpdate) override;
void SetScissorRect(const EFBRectangle& rc) override;
void SetGenerationMode() override;
void SetDepthMode() override;
void SetLogicOpMode() override;
void SetDitherMode() override;
void SetSamplerState(int stage, int texindex, bool custom_tex) override;
void SetInterlacingMode() override;
void SetViewport() override;
void SetColorMask() override;
void SetBlendMode(bool forceUpdate) override;
void SetScissorRect(const EFBRectangle& rc) override;
void SetGenerationMode() override;
void SetDepthMode() override;
void SetLogicOpMode() override;
void SetDitherMode() override;
void SetSamplerState(int stage, int texindex, bool custom_tex) override;
void SetInterlacingMode() override;
void SetViewport() override;
// TODO: Fix confusing names (see ResetAPIState and RestoreAPIState)
void ApplyState(bool bUseDstAlpha) override;
void RestoreState() override;
// TODO: Fix confusing names (see ResetAPIState and RestoreAPIState)
void ApplyState(bool bUseDstAlpha) override;
void RestoreState() override;
void ApplyCullDisable();
void RestoreCull();
void ApplyCullDisable();
void RestoreCull();
void RenderText(const std::string& text, int left, int top, u32 color) override;
void RenderText(const std::string& text, int left, int top, u32 color) 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;
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;
u16 BBoxRead(int index) override;
void BBoxWrite(int index, u16 value) override;
void ResetAPIState() override;
void RestoreAPIState() override;
void ResetAPIState() override;
void RestoreAPIState() override;
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) override;
void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,
float Gamma) override;
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override;
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
u32 color, u32 z) override;
void ReinterpretPixelData(unsigned int convtype) override;
void ReinterpretPixelData(unsigned int convtype) override;
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc) override;
bool SaveScreenshot(const std::string& filename, const TargetRectangle& rc) override;
static bool CheckForResize();
static bool CheckForResize();
int GetMaxTextureSize() override;
int GetMaxTextureSize() override;
private:
void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float Gamma);
void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture,
u32 src_width, u32 src_height, float Gamma);
};
}

View File

@ -15,157 +15,150 @@
namespace DX11
{
static const char YUYV_DECODER_PS[] =
"// dolphin-emu YUYV decoder pixel shader\n"
"// dolphin-emu YUYV decoder pixel shader\n"
"Texture2D Tex0 : register(t0);\n"
"sampler Samp0 : register(s0);\n"
"Texture2D Tex0 : register(t0);\n"
"sampler Samp0 : register(s0);\n"
"static const float3x3 YCBCR_TO_RGB = float3x3(\n"
"1.164, 0.000, 1.596,\n"
"1.164, -0.392, -0.813,\n"
"1.164, 2.017, 0.000\n"
");\n"
"static const float3x3 YCBCR_TO_RGB = float3x3(\n"
"1.164, 0.000, 1.596,\n"
"1.164, -0.392, -0.813,\n"
"1.164, 2.017, 0.000\n"
");\n"
"void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : TEXCOORD0)\n"
"{\n"
"float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n"
"void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : "
"TEXCOORD0)\n"
"{\n"
"float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n"
// GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color
// primaries, compressed to the range Y in 16..235, U and V in 16..240.
// We want to convert it to RGB format with sRGB color primaries, with
// range 0..255.
// GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color
// primaries, compressed to the range Y in 16..235, U and V in 16..240.
// We want to convert it to RGB format with sRGB color primaries, with
// range 0..255.
// Recover RGB components
"float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n"
"float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n"
// Recover RGB components
"float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n"
"float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n"
// If we were really obsessed with accuracy, we would correct for the
// differing color primaries between BT.601 and sRGB. However, this may not
// be worth the trouble because:
// - BT.601 defines two sets of primaries: one for NTSC and one for PAL.
// - sRGB's color primaries are actually an intermediate between BT.601's
// NTSC and PAL primaries.
// - If users even noticed any difference at all, they would be confused by
// the slightly-different colors in the NTSC and PAL versions of the same
// game.
// - Even the game designers probably don't pay close attention to this
// stuff.
// Still, instructions on how to do it can be found at
// <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC20>
// If we were really obsessed with accuracy, we would correct for the
// differing color primaries between BT.601 and sRGB. However, this may not
// be worth the trouble because:
// - BT.601 defines two sets of primaries: one for NTSC and one for PAL.
// - sRGB's color primaries are actually an intermediate between BT.601's
// NTSC and PAL primaries.
// - If users even noticed any difference at all, they would be confused by
// the slightly-different colors in the NTSC and PAL versions of the same
// game.
// - Even the game designers probably don't pay close attention to this
// stuff.
// Still, instructions on how to do it can be found at
// <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC20>
"ocol0 = float4(rgb_601, 1);\n"
"}\n"
;
"ocol0 = float4(rgb_601, 1);\n"
"}\n";
Television::Television()
: m_yuyvTexture(nullptr), m_yuyvTextureSRV(nullptr), m_pShader(nullptr)
{ }
Television::Television() : m_yuyvTexture(nullptr), m_yuyvTextureSRV(nullptr), m_pShader(nullptr)
{
}
void Television::Init()
{
HRESULT hr;
HRESULT hr;
// Create YUYV texture for real XFB mode
// Create YUYV texture for real XFB mode
// Initialize the texture with YCbCr black
//
// Some games use narrower XFB widths (Nintendo titles are fond of 608),
// so the sampler's BorderColor won't cover the right side
// (see sampler state below)
const unsigned int MAX_XFB_SIZE = 2 * (MAX_XFB_WIDTH)*MAX_XFB_HEIGHT;
std::vector<u8> fill(MAX_XFB_SIZE);
for (size_t i = 0; i < MAX_XFB_SIZE / sizeof(u32); ++i)
reinterpret_cast<u32*>(fill.data())[i] = 0x80108010;
D3D11_SUBRESOURCE_DATA srd = {fill.data(), 2 * (MAX_XFB_WIDTH), 0};
// Initialize the texture with YCbCr black
//
// Some games use narrower XFB widths (Nintendo titles are fond of 608),
// so the sampler's BorderColor won't cover the right side
// (see sampler state below)
const unsigned int MAX_XFB_SIZE = 2*(MAX_XFB_WIDTH) * MAX_XFB_HEIGHT;
std::vector<u8> fill(MAX_XFB_SIZE);
for (size_t i = 0; i < MAX_XFB_SIZE / sizeof(u32); ++i)
reinterpret_cast<u32*>(fill.data())[i] = 0x80108010;
D3D11_SUBRESOURCE_DATA srd = { fill.data(), 2*(MAX_XFB_WIDTH), 0 };
// This texture format is designed for YUYV data.
D3D11_TEXTURE2D_DESC t2dd =
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1);
hr = D3D::device->CreateTexture2D(&t2dd, &srd, &m_yuyvTexture);
CHECK(SUCCEEDED(hr), "create tv yuyv texture");
D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture");
// This texture format is designed for YUYV data.
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1);
hr = D3D::device->CreateTexture2D(&t2dd, &srd, &m_yuyvTexture);
CHECK(SUCCEEDED(hr), "create tv yuyv texture");
D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture");
// Create shader resource view for YUYV texture
// Create shader resource view for YUYV texture
D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC(
m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_G8R8_G8B8_UNORM);
hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV);
CHECK(SUCCEEDED(hr), "create tv yuyv texture srv");
D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv");
D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC(
m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D,
DXGI_FORMAT_G8R8_G8B8_UNORM);
hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV);
CHECK(SUCCEEDED(hr), "create tv yuyv texture srv");
D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv");
// Create YUYV-decoding pixel shader
// Create YUYV-decoding pixel shader
m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS);
CHECK(m_pShader != nullptr, "compile and create yuyv decoder pixel shader");
D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader");
m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS);
CHECK(m_pShader != nullptr, "compile and create yuyv decoder pixel shader");
D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader");
// Create sampler state and set border color
//
// The default sampler border color of { 0.f, 0.f, 0.f, 0.f }
// creates a green border around the image - see issue 6483
// (remember, the XFB is being interpreted as YUYV, and 0,0,0,0
// is actually two green pixels in YUYV - black should be 16,128,16,128,
// but we reverse the order to match DXGI_FORMAT_G8R8_G8B8_UNORM's ordering)
float border[4] = { 128.0f/255.0f, 16.0f/255.0f, 128.0f/255.0f, 16.0f/255.0f };
D3D11_SAMPLER_DESC 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, &m_samplerState);
CHECK(SUCCEEDED(hr), "create yuyv decoder sampler state");
D3D::SetDebugObjectName(m_samplerState, "yuyv decoder sampler state");
// Create sampler state and set border color
//
// The default sampler border color of { 0.f, 0.f, 0.f, 0.f }
// creates a green border around the image - see issue 6483
// (remember, the XFB is being interpreted as YUYV, and 0,0,0,0
// is actually two green pixels in YUYV - black should be 16,128,16,128,
// but we reverse the order to match DXGI_FORMAT_G8R8_G8B8_UNORM's ordering)
float border[4] = {128.0f / 255.0f, 16.0f / 255.0f, 128.0f / 255.0f, 16.0f / 255.0f};
D3D11_SAMPLER_DESC 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, &m_samplerState);
CHECK(SUCCEEDED(hr), "create yuyv decoder sampler state");
D3D::SetDebugObjectName(m_samplerState, "yuyv decoder sampler state");
}
void Television::Shutdown()
{
SAFE_RELEASE(m_pShader);
SAFE_RELEASE(m_yuyvTextureSRV);
SAFE_RELEASE(m_yuyvTexture);
SAFE_RELEASE(m_samplerState);
SAFE_RELEASE(m_pShader);
SAFE_RELEASE(m_yuyvTextureSRV);
SAFE_RELEASE(m_yuyvTexture);
SAFE_RELEASE(m_samplerState);
}
void Television::Submit(u32 xfbAddr, u32 stride, u32 width, u32 height)
{
m_curAddr = xfbAddr;
m_curWidth = width;
m_curHeight = height;
m_curAddr = xfbAddr;
m_curWidth = width;
m_curHeight = height;
// Load data from GameCube RAM to YUYV texture
u8* yuyvSrc = Memory::GetPointer(xfbAddr);
D3D11_BOX box = CD3D11_BOX(0, 0, 0, stride, height, 1);
D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2 * stride, 2 * stride * height);
// Load data from GameCube RAM to YUYV texture
u8* yuyvSrc = Memory::GetPointer(xfbAddr);
D3D11_BOX box = CD3D11_BOX(0, 0, 0, stride, height, 1);
D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2 * stride, 2 * stride * height);
}
void Television::Render()
{
if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB)
{
// Use real XFB mode
// TODO: If this is the lower field, render at a vertical offset of 1
// line down. We could even consider implementing a deinterlacing
// algorithm.
if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB)
{
// Use real XFB mode
// TODO: If this is the lower field, render at a vertical offset of 1
// line down. We could even consider implementing a deinterlacing
// algorithm.
D3D11_RECT sourceRc = CD3D11_RECT(0, 0, int(m_curWidth), int(m_curHeight));
D3D11_RECT sourceRc = CD3D11_RECT(0, 0, int(m_curWidth), int(m_curHeight));
D3D::stateman->SetSampler(0, m_samplerState);
D3D::stateman->SetSampler(0, m_samplerState);
D3D::drawShadedTexQuad(
m_yuyvTextureSRV, &sourceRc,
MAX_XFB_WIDTH, MAX_XFB_HEIGHT,
m_pShader,
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout());
}
else if (g_ActiveConfig.bUseXFB)
{
// Use virtual XFB mode
D3D::drawShadedTexQuad(m_yuyvTextureSRV, &sourceRc, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, m_pShader,
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout());
}
else if (g_ActiveConfig.bUseXFB)
{
// Use virtual XFB mode
// TODO: Eventually, Television should render the Virtual XFB mode
// display as well.
}
// TODO: Eventually, Television should render the Virtual XFB mode
// display as well.
}
}
}

View File

@ -13,39 +13,33 @@ struct ID3D11SamplerState;
namespace DX11
{
class Television
{
public:
Television();
Television();
void Init();
void Shutdown();
void Init();
void Shutdown();
// Submit video data to be drawn. This will change the current state of the
// TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB
// may be virtualized when rendering so the RAM may not actually be read.
void Submit(u32 xfbAddr, u32 stride, u32 width, u32 height);
// Submit video data to be drawn. This will change the current state of the
// TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB
// may be virtualized when rendering so the RAM may not actually be read.
void Submit(u32 xfbAddr, u32 stride, u32 width, u32 height);
// Render the current state of the TV.
void Render();
// Render the current state of the TV.
void Render();
private:
// Properties of last Submit call
u32 m_curAddr;
u32 m_curWidth;
u32 m_curHeight;
// Properties of last Submit call
u32 m_curAddr;
u32 m_curWidth;
u32 m_curHeight;
// Used for real XFB mode
ID3D11Texture2D* m_yuyvTexture;
ID3D11ShaderResourceView* m_yuyvTextureSRV;
ID3D11PixelShader* m_pShader;
ID3D11SamplerState* m_samplerState;
// Used for real XFB mode
ID3D11Texture2D* m_yuyvTexture;
ID3D11ShaderResourceView* m_yuyvTextureSRV;
ID3D11PixelShader* m_pShader;
ID3D11SamplerState* m_samplerState;
};
}

View File

@ -10,8 +10,8 @@
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/FramebufferManager.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/PSTextureEncoder.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/TextureCache.h"
#include "VideoBackends/D3D/TextureEncoder.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
@ -22,249 +22,246 @@
namespace DX11
{
static std::unique_ptr<TextureEncoder> g_encoder;
const size_t MAX_COPY_BUFFERS = 32;
ID3D11Buffer* efbcopycbuf[MAX_COPY_BUFFERS] = { 0 };
ID3D11Buffer* efbcopycbuf[MAX_COPY_BUFFERS] = {0};
TextureCache::TCacheEntry::~TCacheEntry()
{
texture->Release();
texture->Release();
}
void TextureCache::TCacheEntry::Bind(unsigned int stage)
{
D3D::stateman->SetTexture(stage, texture->GetSRV());
D3D::stateman->SetTexture(stage, texture->GetSRV());
}
bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int level)
{
// TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs)
static bool warn_once = true;
if (level && warn_once)
{
WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D11 backend!");
warn_once = false;
return false;
}
// TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs)
static bool warn_once = true;
if (level && warn_once)
{
WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D11 backend!");
warn_once = false;
return false;
}
ID3D11Texture2D* pNewTexture = nullptr;
ID3D11Texture2D* pSurface = texture->GetTex();
D3D11_TEXTURE2D_DESC desc;
pSurface->GetDesc(&desc);
ID3D11Texture2D* pNewTexture = nullptr;
ID3D11Texture2D* pSurface = texture->GetTex();
D3D11_TEXTURE2D_DESC desc;
pSurface->GetDesc(&desc);
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.Usage = D3D11_USAGE_STAGING;
HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &pNewTexture);
HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &pNewTexture);
bool saved_png = false;
bool saved_png = false;
if (SUCCEEDED(hr) && pNewTexture)
{
D3D::context->CopyResource(pNewTexture, pSurface);
if (SUCCEEDED(hr) && pNewTexture)
{
D3D::context->CopyResource(pNewTexture, pSurface);
D3D11_MAPPED_SUBRESOURCE map;
hr = D3D::context->Map(pNewTexture, 0, D3D11_MAP_READ_WRITE, 0, &map);
if (SUCCEEDED(hr))
{
saved_png = TextureToPng((u8*)map.pData, map.RowPitch, filename, desc.Width, desc.Height);
D3D::context->Unmap(pNewTexture, 0);
}
SAFE_RELEASE(pNewTexture);
}
D3D11_MAPPED_SUBRESOURCE map;
hr = D3D::context->Map(pNewTexture, 0, D3D11_MAP_READ_WRITE, 0, &map);
if (SUCCEEDED(hr))
{
saved_png = TextureToPng((u8*)map.pData, map.RowPitch, filename, desc.Width, desc.Height);
D3D::context->Unmap(pNewTexture, 0);
}
SAFE_RELEASE(pNewTexture);
}
return saved_png;
return saved_png;
}
void TextureCache::TCacheEntry::CopyRectangleFromTexture(
const TCacheEntryBase* source,
const MathUtil::Rectangle<int> &srcrect,
const MathUtil::Rectangle<int> &dstrect)
void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* source,
const MathUtil::Rectangle<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect)
{
TCacheEntry* srcentry = (TCacheEntry*)source;
if (srcrect.GetWidth() == dstrect.GetWidth()
&& srcrect.GetHeight() == dstrect.GetHeight())
{
D3D11_BOX srcbox;
srcbox.left = srcrect.left;
srcbox.top = srcrect.top;
srcbox.right = srcrect.right;
srcbox.bottom = srcrect.bottom;
srcbox.front = 0;
srcbox.back = srcentry->config.layers;
TCacheEntry* srcentry = (TCacheEntry*)source;
if (srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight())
{
D3D11_BOX srcbox;
srcbox.left = srcrect.left;
srcbox.top = srcrect.top;
srcbox.right = srcrect.right;
srcbox.bottom = srcrect.bottom;
srcbox.front = 0;
srcbox.back = srcentry->config.layers;
D3D::context->CopySubresourceRegion(
texture->GetTex(),
0,
dstrect.left,
dstrect.top,
0,
srcentry->texture->GetTex(),
0,
&srcbox);
return;
}
else if (!config.rendertarget)
{
return;
}
g_renderer->ResetAPIState(); // reset any game specific settings
D3D::context->CopySubresourceRegion(texture->GetTex(), 0, dstrect.left, dstrect.top, 0,
srcentry->texture->GetTex(), 0, &srcbox);
return;
}
else if (!config.rendertarget)
{
return;
}
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()));
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(float(dstrect.left), float(dstrect.top),
float(dstrect.GetWidth()), float(dstrect.GetHeight()));
D3D::stateman->UnsetTexture(texture->GetSRV());
D3D::stateman->Apply();
D3D::stateman->UnsetTexture(texture->GetSRV());
D3D::stateman->Apply();
D3D::context->OMSetRenderTargets(1, &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->texture->GetSRV(), &srcRC,
srcentry->config.width, srcentry->config.height,
PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0);
D3D::context->OMSetRenderTargets(1, &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->texture->GetSRV(), &srcRC, srcentry->config.width,
srcentry->config.height, PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0);
D3D::context->OMSetRenderTargets(1,
&FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
g_renderer->RestoreAPIState();
}
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level)
unsigned int expanded_width, unsigned int level)
{
unsigned int src_pitch = 4 * expanded_width;
D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, src_pitch, level, usage);
unsigned int src_pitch = 4 * expanded_width;
D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, src_pitch, level,
usage);
}
TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config)
{
if (config.rendertarget)
{
return new TCacheEntry(config, D3DTexture2D::Create(config.width, config.height,
(D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE),
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers));
}
else
{
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0;
if (config.rendertarget)
{
return new TCacheEntry(
config, D3DTexture2D::Create(
config.width, config.height, (D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET |
(int)D3D11_BIND_SHADER_RESOURCE),
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers));
}
else
{
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0;
if (config.levels == 1)
{
usage = D3D11_USAGE_DYNAMIC;
cpu_access = D3D11_CPU_ACCESS_WRITE;
}
if (config.levels == 1)
{
usage = D3D11_USAGE_DYNAMIC;
cpu_access = D3D11_CPU_ACCESS_WRITE;
}
const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM,
config.width, config.height, 1, config.levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
const D3D11_TEXTURE2D_DESC texdesc =
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, config.width, config.height, 1,
config.levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
ID3D11Texture2D *pTexture;
const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
ID3D11Texture2D* pTexture;
const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
TCacheEntry* const entry = new TCacheEntry(config, new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE));
entry->usage = usage;
TCacheEntry* const entry =
new TCacheEntry(config, new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE));
entry->usage = usage;
// TODO: better debug names
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), "a texture of the TextureCache");
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache");
// TODO: better debug names
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(),
"a texture of the TextureCache");
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(),
"shader resource view of a texture of the TextureCache");
SAFE_RELEASE(pTexture);
SAFE_RELEASE(pTexture);
return entry;
}
return entry;
}
}
void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool scaleByHalf, unsigned int cbufid, const float *colmat)
void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat,
const EFBRectangle& srcRect, bool scaleByHalf,
unsigned int cbufid, const float* colmat)
{
// When copying at half size, in multisampled mode, resolve the color/depth buffer first.
// This is because multisampled texture reads go through Load, not Sample, and the linear
// filter is ignored.
bool multisampled = (g_ActiveConfig.iMultisamples > 1);
ID3D11ShaderResourceView* efbTexSRV = (srcFormat == PEControl::Z24) ?
FramebufferManager::GetEFBDepthTexture()->GetSRV() :
FramebufferManager::GetEFBColorTexture()->GetSRV();
if (multisampled && scaleByHalf)
{
multisampled = false;
efbTexSRV = (srcFormat == PEControl::Z24) ?
FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() :
FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
}
// When copying at half size, in multisampled mode, resolve the color/depth buffer first.
// This is because multisampled texture reads go through Load, not Sample, and the linear
// filter is ignored.
bool multisampled = (g_ActiveConfig.iMultisamples > 1);
ID3D11ShaderResourceView* efbTexSRV = (srcFormat == PEControl::Z24) ?
FramebufferManager::GetEFBDepthTexture()->GetSRV() :
FramebufferManager::GetEFBColorTexture()->GetSRV();
if (multisampled && scaleByHalf)
{
multisampled = false;
efbTexSRV = (srcFormat == PEControl::Z24) ?
FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() :
FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
}
g_renderer->ResetAPIState();
g_renderer->ResetAPIState();
// stretch picture with increased internal resolution
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)config.width, (float)config.height);
D3D::context->RSSetViewports(1, &vp);
// stretch picture with increased internal resolution
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)config.width, (float)config.height);
D3D::context->RSSetViewports(1, &vp);
// set transformation
if (nullptr == efbcopycbuf[cbufid])
{
const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(28 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = colmat;
HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]);
CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid);
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], "a constant buffer used in TextureCache::CopyRenderTargetToTexture");
}
D3D::stateman->SetPixelConstants(efbcopycbuf[cbufid]);
// set transformation
if (nullptr == efbcopycbuf[cbufid])
{
const D3D11_BUFFER_DESC cbdesc =
CD3D11_BUFFER_DESC(28 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = colmat;
HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]);
CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid);
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid],
"a constant buffer used in TextureCache::CopyRenderTargetToTexture");
}
D3D::stateman->SetPixelConstants(efbcopycbuf[cbufid]);
const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect);
// TODO: try targetSource.asRECT();
const D3D11_RECT sourcerect = CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom);
const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect);
// 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 (scaleByHalf)
D3D::SetLinearCopySampler();
else
D3D::SetPointCopySampler();
// Use linear filtering if (bScaleByHalf), use point filtering otherwise
if (scaleByHalf)
D3D::SetLinearCopySampler();
else
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(texture->GetSRV());
D3D::stateman->Apply();
// 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(texture->GetSRV());
D3D::stateman->Apply();
D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr);
D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr);
// Create texture copy
D3D::drawShadedTexQuad(
efbTexSRV,
&sourcerect, Renderer::GetTargetWidth(),
Renderer::GetTargetHeight(),
srcFormat == PEControl::Z24 ? PixelShaderCache::GetDepthMatrixProgram(multisampled) : PixelShaderCache::GetColorMatrixProgram(multisampled),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader());
// Create texture copy
D3D::drawShadedTexQuad(
efbTexSRV, &sourcerect, Renderer::GetTargetWidth(), Renderer::GetTargetHeight(),
srcFormat == PEControl::Z24 ? PixelShaderCache::GetDepthMatrixProgram(multisampled) :
PixelShaderCache::GetColorMatrixProgram(multisampled),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
g_renderer->RestoreAPIState();
}
void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf)
void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row,
u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf)
{
g_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, srcFormat, srcRect, isIntensity, scaleByHalf);
g_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride,
srcFormat, srcRect, isIntensity, scaleByHalf);
}
const char palette_shader[] =
R"HLSL(
R"HLSL(
sampler samp0 : register(s0);
Texture2DArray Tex0 : register(t0);
Buffer<uint> Tex1 : register(t1);
@ -343,97 +340,103 @@ void main(
}
)HLSL";
void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format)
void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted,
void* palette, TlutFormat format)
{
g_renderer->ResetAPIState();
g_renderer->ResetAPIState();
// stretch picture with increased internal resolution
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)unconverted->config.width, (float)unconverted->config.height);
D3D::context->RSSetViewports(1, &vp);
// stretch picture with increased internal resolution
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)unconverted->config.width,
(float)unconverted->config.height);
D3D::context->RSSetViewports(1, &vp);
D3D11_BOX box{ 0, 0, 0, 512, 1, 1 };
D3D::context->UpdateSubresource(palette_buf, 0, &box, palette, 0, 0);
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);
D3D::stateman->SetTexture(1, palette_buf_srv);
// TODO: Add support for C14X2 format. (Different multiplier, more palette entries.)
float params[4] = { (unconverted->format & 0xf) == GX_TF_I4 ? 15.f : 255.f };
D3D::context->UpdateSubresource(palette_uniform, 0, nullptr, &params, 0, 0);
D3D::stateman->SetPixelConstants(palette_uniform);
// TODO: Add support for C14X2 format. (Different multiplier, more palette entries.)
float params[4] = {(unconverted->format & 0xf) == GX_TF_I4 ? 15.f : 255.f};
D3D::context->UpdateSubresource(palette_uniform, 0, nullptr, &params, 0, 0);
D3D::stateman->SetPixelConstants(palette_uniform);
const D3D11_RECT sourcerect = CD3D11_RECT(0, 0, unconverted->config.width, unconverted->config.height);
const D3D11_RECT sourcerect =
CD3D11_RECT(0, 0, unconverted->config.width, unconverted->config.height);
D3D::SetPointCopySampler();
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(static_cast<TCacheEntry*>(entry)->texture->GetSRV());
D3D::stateman->Apply();
// 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(static_cast<TCacheEntry*>(entry)->texture->GetSRV());
D3D::stateman->Apply();
D3D::context->OMSetRenderTargets(1, &static_cast<TCacheEntry*>(entry)->texture->GetRTV(), nullptr);
D3D::context->OMSetRenderTargets(1, &static_cast<TCacheEntry*>(entry)->texture->GetRTV(),
nullptr);
// Create texture copy
D3D::drawShadedTexQuad(
static_cast<TCacheEntry*>(unconverted)->texture->GetSRV(),
&sourcerect, unconverted->config.width, unconverted->config.height,
palette_pixel_shader[format],
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader());
// Create texture copy
D3D::drawShadedTexQuad(static_cast<TCacheEntry*>(unconverted)->texture->GetSRV(), &sourcerect,
unconverted->config.width, unconverted->config.height,
palette_pixel_shader[format], VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
g_renderer->RestoreAPIState();
}
ID3D11PixelShader *GetConvertShader(const char* Type)
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);
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();
// FIXME: Is it safe here?
g_encoder = std::make_unique<PSTextureEncoder>();
g_encoder->Init();
palette_buf = nullptr;
palette_buf_srv = nullptr;
palette_uniform = nullptr;
palette_pixel_shader[GX_TL_IA8] = GetConvertShader("IA8");
palette_pixel_shader[GX_TL_RGB565] = GetConvertShader("RGB565");
palette_pixel_shader[GX_TL_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(16, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &palette_uniform);
CHECK(SUCCEEDED(hr), "Create palette decoder constant buffer");
D3D::SetDebugObjectName((ID3D11DeviceChild*)palette_uniform, "a constant buffer used in TextureCache::CopyRenderTargetToTexture");
palette_buf = nullptr;
palette_buf_srv = nullptr;
palette_uniform = nullptr;
palette_pixel_shader[GX_TL_IA8] = GetConvertShader("IA8");
palette_pixel_shader[GX_TL_RGB565] = GetConvertShader("RGB565");
palette_pixel_shader[GX_TL_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(16, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &palette_uniform);
CHECK(SUCCEEDED(hr), "Create palette decoder constant buffer");
D3D::SetDebugObjectName((ID3D11DeviceChild*)palette_uniform,
"a constant buffer used in TextureCache::CopyRenderTargetToTexture");
}
TextureCache::~TextureCache()
{
for (unsigned int k = 0; k < MAX_COPY_BUFFERS; ++k)
SAFE_RELEASE(efbcopycbuf[k]);
for (unsigned int k = 0; k < MAX_COPY_BUFFERS; ++k)
SAFE_RELEASE(efbcopycbuf[k]);
g_encoder->Shutdown();
g_encoder.reset();
g_encoder->Shutdown();
g_encoder.reset();
SAFE_RELEASE(palette_buf);
SAFE_RELEASE(palette_buf_srv);
SAFE_RELEASE(palette_uniform);
for (ID3D11PixelShader*& shader : palette_pixel_shader)
SAFE_RELEASE(shader);
SAFE_RELEASE(palette_buf);
SAFE_RELEASE(palette_buf_srv);
SAFE_RELEASE(palette_uniform);
for (ID3D11PixelShader*& shader : palette_pixel_shader)
SAFE_RELEASE(shader);
}
}

View File

@ -9,55 +9,60 @@
namespace DX11
{
class TextureCache : public TextureCacheBase
{
public:
TextureCache();
~TextureCache();
TextureCache();
~TextureCache();
private:
struct TCacheEntry : TCacheEntryBase
{
D3DTexture2D *const texture;
struct TCacheEntry : TCacheEntryBase
{
D3DTexture2D* const texture;
D3D11_USAGE usage;
D3D11_USAGE usage;
TCacheEntry(const TCacheEntryConfig& config, D3DTexture2D *_tex) : TCacheEntryBase(config), texture(_tex) {}
~TCacheEntry();
TCacheEntry(const TCacheEntryConfig& config, D3DTexture2D* _tex)
: TCacheEntryBase(config), texture(_tex)
{
}
~TCacheEntry();
void CopyRectangleFromTexture(
const TCacheEntryBase* source,
const MathUtil::Rectangle<int> &srcrect,
const MathUtil::Rectangle<int> &dstrect) override;
void CopyRectangleFromTexture(const TCacheEntryBase* source,
const MathUtil::Rectangle<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect) override;
void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int levels) override;
void Load(unsigned int width, unsigned int height, unsigned int expanded_width,
unsigned int levels) override;
void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool scaleByHalf, unsigned int cbufid, const float *colmat) override;
void FromRenderTarget(u8* dst, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool scaleByHalf, unsigned int cbufid, const float* colmat) override;
void Bind(unsigned int stage) override;
bool Save(const std::string& filename, unsigned int level) override;
};
void Bind(unsigned int stage) override;
bool Save(const std::string& filename, unsigned int level) override;
};
TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override;
TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override;
u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) {return 0;};
u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 SourceW, u32 SourceH,
bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf,
const EFBRectangle& source)
{
return 0;
};
void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override;
void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette,
TlutFormat format) override;
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf) override;
void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y,
u32 memory_stride, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf) override;
void CompileShaders() override { }
void DeleteShaders() override { }
ID3D11Buffer* palette_buf;
ID3D11ShaderResourceView* palette_buf_srv;
ID3D11Buffer* palette_uniform;
ID3D11PixelShader* palette_pixel_shader[3];
void CompileShaders() override {}
void DeleteShaders() override {}
ID3D11Buffer* palette_buf;
ID3D11ShaderResourceView* palette_buf_srv;
ID3D11Buffer* palette_uniform;
ID3D11PixelShader* palette_pixel_shader[3];
};
}

View File

@ -12,24 +12,19 @@ namespace DX11
{
// Maximum number of bytes that can occur in a texture block-row generated by
// the encoder
static const UINT MAX_BYTES_PER_BLOCK_ROW = (EFB_WIDTH/4)*64;
static const UINT MAX_BYTES_PER_BLOCK_ROW = (EFB_WIDTH / 4) * 64;
// The maximum amount of data that the texture encoder can generate in one call
static const UINT MAX_BYTES_PER_ENCODE = MAX_BYTES_PER_BLOCK_ROW*(EFB_HEIGHT/4);
static const UINT MAX_BYTES_PER_ENCODE = MAX_BYTES_PER_BLOCK_ROW * (EFB_HEIGHT / 4);
class TextureEncoder
{
public:
virtual ~TextureEncoder() { }
virtual void Init() = 0;
virtual void Shutdown() = 0;
// Returns size in bytes of encoded block of memory
virtual void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf) = 0;
virtual ~TextureEncoder() {}
virtual void Init() = 0;
virtual void Shutdown() = 0;
// Returns size in bytes of encoded block of memory
virtual void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y,
u32 memory_stride, PEControl::PixelFormat srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) = 0;
};
}

View File

@ -23,7 +23,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;
@ -31,164 +30,166 @@ const u32 MAX_BUFFER_SIZE = MAX_IBUFFER_SIZE + MAX_VBUFFER_SIZE;
void VertexManager::CreateDeviceObjects()
{
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);
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);
m_vertexDrawOffset = 0;
m_indexDrawOffset = 0;
m_vertexDrawOffset = 0;
m_indexDrawOffset = 0;
for (int i = 0; i < MAX_BUFFER_COUNT; i++)
{
m_buffers[i] = nullptr;
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, nullptr, &m_buffers[i])), "Failed to create buffer.");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_buffers[i], "Buffer of VertexManager");
}
for (int i = 0; i < MAX_BUFFER_COUNT; i++)
{
m_buffers[i] = nullptr;
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, nullptr, &m_buffers[i])),
"Failed to create buffer.");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_buffers[i], "Buffer of VertexManager");
}
m_currentBuffer = 0;
m_bufferCursor = MAX_BUFFER_SIZE;
m_currentBuffer = 0;
m_bufferCursor = MAX_BUFFER_SIZE;
}
void VertexManager::DestroyDeviceObjects()
{
for (int i = 0; i < MAX_BUFFER_COUNT; i++)
{
SAFE_RELEASE(m_buffers[i]);
}
for (int i = 0; i < MAX_BUFFER_COUNT; i++)
{
SAFE_RELEASE(m_buffers[i]);
}
}
VertexManager::VertexManager()
{
LocalVBuffer.resize(MAXVBUFFERSIZE);
LocalVBuffer.resize(MAXVBUFFERSIZE);
s_pCurBufferPointer = s_pBaseBufferPointer = &LocalVBuffer[0];
s_pEndBufferPointer = s_pBaseBufferPointer + LocalVBuffer.size();
s_pCurBufferPointer = s_pBaseBufferPointer = &LocalVBuffer[0];
s_pEndBufferPointer = s_pBaseBufferPointer + LocalVBuffer.size();
LocalIBuffer.resize(MAXIBUFFERSIZE);
LocalIBuffer.resize(MAXIBUFFERSIZE);
CreateDeviceObjects();
CreateDeviceObjects();
}
VertexManager::~VertexManager()
{
DestroyDeviceObjects();
DestroyDeviceObjects();
}
void VertexManager::PrepareDrawBuffers(u32 stride)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D11_MAPPED_SUBRESOURCE map;
u32 vertexBufferSize = u32(s_pCurBufferPointer - s_pBaseBufferPointer);
u32 indexBufferSize = IndexGenerator::GetIndexLen() * sizeof(u16);
u32 totalBufferSize = vertexBufferSize + indexBufferSize;
u32 vertexBufferSize = u32(s_pCurBufferPointer - s_pBaseBufferPointer);
u32 indexBufferSize = IndexGenerator::GetIndexLen() * sizeof(u16);
u32 totalBufferSize = vertexBufferSize + indexBufferSize;
u32 cursor = m_bufferCursor;
u32 padding = m_bufferCursor % stride;
if (padding)
{
cursor += stride - padding;
}
u32 cursor = m_bufferCursor;
u32 padding = m_bufferCursor % stride;
if (padding)
{
cursor += stride - padding;
}
D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
if (cursor + totalBufferSize >= MAX_BUFFER_SIZE)
{
// Wrap around
m_currentBuffer = (m_currentBuffer + 1) % MAX_BUFFER_COUNT;
cursor = 0;
MapType = D3D11_MAP_WRITE_DISCARD;
}
D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
if (cursor + totalBufferSize >= MAX_BUFFER_SIZE)
{
// Wrap around
m_currentBuffer = (m_currentBuffer + 1) % MAX_BUFFER_COUNT;
cursor = 0;
MapType = D3D11_MAP_WRITE_DISCARD;
}
m_vertexDrawOffset = cursor;
m_indexDrawOffset = cursor + vertexBufferSize;
m_vertexDrawOffset = cursor;
m_indexDrawOffset = cursor + vertexBufferSize;
D3D::context->Map(m_buffers[m_currentBuffer], 0, MapType, 0, &map);
u8* mappedData = reinterpret_cast<u8*>(map.pData);
memcpy(mappedData + m_vertexDrawOffset, s_pBaseBufferPointer, vertexBufferSize);
memcpy(mappedData + m_indexDrawOffset, GetIndexBuffer(), indexBufferSize);
D3D::context->Unmap(m_buffers[m_currentBuffer], 0);
D3D::context->Map(m_buffers[m_currentBuffer], 0, MapType, 0, &map);
u8* mappedData = reinterpret_cast<u8*>(map.pData);
memcpy(mappedData + m_vertexDrawOffset, s_pBaseBufferPointer, vertexBufferSize);
memcpy(mappedData + m_indexDrawOffset, GetIndexBuffer(), indexBufferSize);
D3D::context->Unmap(m_buffers[m_currentBuffer], 0);
m_bufferCursor = cursor + totalBufferSize;
m_bufferCursor = cursor + totalBufferSize;
ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertexBufferSize);
ADDSTAT(stats.thisFrame.bytesIndexStreamed, indexBufferSize);
ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertexBufferSize);
ADDSTAT(stats.thisFrame.bytesIndexStreamed, indexBufferSize);
}
void VertexManager::Draw(u32 stride)
{
u32 indices = IndexGenerator::GetIndexLen();
u32 indices = IndexGenerator::GetIndexLen();
D3D::stateman->SetVertexBuffer(m_buffers[m_currentBuffer], stride, 0);
D3D::stateman->SetIndexBuffer(m_buffers[m_currentBuffer]);
D3D::stateman->SetVertexBuffer(m_buffers[m_currentBuffer], stride, 0);
D3D::stateman->SetIndexBuffer(m_buffers[m_currentBuffer]);
u32 baseVertex = m_vertexDrawOffset / stride;
u32 startIndex = m_indexDrawOffset / sizeof(u16);
u32 baseVertex = m_vertexDrawOffset / stride;
u32 startIndex = m_indexDrawOffset / sizeof(u16);
switch (current_primitive_type)
{
case PRIMITIVE_POINTS:
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
static_cast<Renderer*>(g_renderer.get())->ApplyCullDisable();
break;
case PRIMITIVE_LINES:
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
static_cast<Renderer*>(g_renderer.get())->ApplyCullDisable();
break;
case PRIMITIVE_TRIANGLES:
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
break;
}
switch (current_primitive_type)
{
case PRIMITIVE_POINTS:
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
static_cast<Renderer*>(g_renderer.get())->ApplyCullDisable();
break;
case PRIMITIVE_LINES:
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
static_cast<Renderer*>(g_renderer.get())->ApplyCullDisable();
break;
case PRIMITIVE_TRIANGLES:
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
break;
}
D3D::stateman->Apply();
D3D::context->DrawIndexed(indices, startIndex, baseVertex);
D3D::stateman->Apply();
D3D::context->DrawIndexed(indices, startIndex, baseVertex);
INCSTAT(stats.thisFrame.numDrawCalls);
INCSTAT(stats.thisFrame.numDrawCalls);
if (current_primitive_type != PRIMITIVE_TRIANGLES)
static_cast<Renderer*>(g_renderer.get())->RestoreCull();
if (current_primitive_type != PRIMITIVE_TRIANGLES)
static_cast<Renderer*>(g_renderer.get())->RestoreCull();
}
void VertexManager::vFlush(bool useDstAlpha)
{
if (!PixelShaderCache::SetShader(
useDstAlpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE))
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
return;
}
if (!PixelShaderCache::SetShader(useDstAlpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE))
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); });
return;
}
if (!VertexShaderCache::SetShader())
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
return;
}
if (!VertexShaderCache::SetShader())
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); });
return;
}
if (!GeometryShaderCache::SetShader(current_primitive_type))
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); });
return;
}
if (!GeometryShaderCache::SetShader(current_primitive_type))
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); });
return;
}
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);
}
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);
}
u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride();
u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride();
PrepareDrawBuffers(stride);
PrepareDrawBuffers(stride);
VertexLoaderManager::GetCurrentVertexFormat()->SetupVertexPointers();
g_renderer->ApplyState(useDstAlpha);
VertexLoaderManager::GetCurrentVertexFormat()->SetupVertexPointers();
g_renderer->ApplyState(useDstAlpha);
Draw(stride);
Draw(stride);
g_renderer->RestoreState();
g_renderer->RestoreState();
}
void VertexManager::ResetBuffer(u32 stride)
{
s_pCurBufferPointer = s_pBaseBufferPointer;
IndexGenerator::Start(GetIndexBuffer());
s_pCurBufferPointer = s_pBaseBufferPointer;
IndexGenerator::Start(GetIndexBuffer());
}
} // namespace

View File

@ -8,38 +8,38 @@
namespace DX11
{
class VertexManager : public VertexManagerBase
{
public:
VertexManager();
~VertexManager();
VertexManager();
~VertexManager();
NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
void CreateDeviceObjects() override;
void DestroyDeviceObjects() override;
NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
void CreateDeviceObjects() override;
void DestroyDeviceObjects() override;
protected:
void ResetBuffer(u32 stride) override;
u16* GetIndexBuffer() { return &LocalIBuffer[0]; }
void ResetBuffer(u32 stride) override;
u16* GetIndexBuffer() { return &LocalIBuffer[0]; }
private:
void PrepareDrawBuffers(u32 stride);
void Draw(u32 stride);
// temp
void vFlush(bool useDstAlpha) override;
void PrepareDrawBuffers(u32 stride);
void Draw(u32 stride);
// temp
void vFlush(bool useDstAlpha) override;
u32 m_vertexDrawOffset;
u32 m_indexDrawOffset;
u32 m_currentBuffer;
u32 m_bufferCursor;
u32 m_vertexDrawOffset;
u32 m_indexDrawOffset;
u32 m_currentBuffer;
u32 m_bufferCursor;
enum
{
MAX_BUFFER_COUNT = 2
};
ID3D11Buffer* m_buffers[MAX_BUFFER_COUNT];
enum { MAX_BUFFER_COUNT = 2 };
ID3D11Buffer* m_buffers[MAX_BUFFER_COUNT];
std::vector<u8> LocalVBuffer;
std::vector<u16> LocalIBuffer;
std::vector<u8> LocalVBuffer;
std::vector<u16> LocalIBuffer;
};
} // namespace

View File

@ -19,10 +19,10 @@
#include "VideoCommon/VertexShaderGen.h"
#include "VideoCommon/VertexShaderManager.h"
namespace DX11 {
namespace DX11
{
VertexShaderCache::VSCache VertexShaderCache::vshaders;
const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry;
const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry;
VertexShaderUid VertexShaderCache::last_uid;
UidChecker<VertexShaderUid, ShaderCode> VertexShaderCache::vertex_uid_checker;
@ -33,232 +33,245 @@ static ID3D11InputLayout* ClearLayout = nullptr;
LinearDiskCache<VertexShaderUid, u8> g_vs_disk_cache;
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() { return SimpleVertexShader; }
ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() { return ClearVertexShader; }
ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout() { return SimpleLayout; }
ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() { return ClearLayout; }
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader()
{
return SimpleVertexShader;
}
ID3D11VertexShader* VertexShaderCache::GetClearVertexShader()
{
return ClearVertexShader;
}
ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout()
{
return SimpleLayout;
}
ID3D11InputLayout* VertexShaderCache::GetClearInputLayout()
{
return ClearLayout;
}
ID3D11Buffer* vscbuf = nullptr;
ID3D11Buffer* &VertexShaderCache::GetConstantBuffer()
ID3D11Buffer*& VertexShaderCache::GetConstantBuffer()
{
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up
if (VertexShaderManager::dirty)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, &VertexShaderManager::constants, sizeof(VertexShaderConstants));
D3D::context->Unmap(vscbuf, 0);
VertexShaderManager::dirty = false;
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to
// speed this up
if (VertexShaderManager::dirty)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, &VertexShaderManager::constants, sizeof(VertexShaderConstants));
D3D::context->Unmap(vscbuf, 0);
VertexShaderManager::dirty = false;
ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(VertexShaderConstants));
}
return vscbuf;
ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(VertexShaderConstants));
}
return vscbuf;
}
// this class will load the precompiled shaders into our cache
class VertexShaderCacheInserter : public LinearDiskCacheReader<VertexShaderUid, u8>
{
public:
void Read(const VertexShaderUid &key, const u8* value, u32 value_size)
{
D3DBlob* blob = new D3DBlob(value_size, value);
VertexShaderCache::InsertByteCode(key, blob);
blob->Release();
}
void Read(const VertexShaderUid& 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"
"float vTexCoord1 : TEXCOORD1;\n"
"};\n"
"VSOUTPUT main(float4 inPosition : POSITION,float4 inTEX0 : TEXCOORD0)\n"
"{\n"
"VSOUTPUT OUT;\n"
"OUT.vPosition = inPosition;\n"
"OUT.vTexCoord = inTEX0.xyz;\n"
"OUT.vTexCoord1 = inTEX0.w;\n"
"return OUT;\n"
"}\n"
};
"struct VSOUTPUT\n"
"{\n"
"float4 vPosition : POSITION;\n"
"float3 vTexCoord : TEXCOORD0;\n"
"float vTexCoord1 : TEXCOORD1;\n"
"};\n"
"VSOUTPUT main(float4 inPosition : POSITION,float4 inTEX0 : TEXCOORD0)\n"
"{\n"
"VSOUTPUT OUT;\n"
"OUT.vPosition = inPosition;\n"
"OUT.vTexCoord = inTEX0.xyz;\n"
"OUT.vTexCoord1 = inTEX0.w;\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"
};
"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 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 },
};
};
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},
};
unsigned int cbsize = ROUND_UP(sizeof(VertexShaderConstants), 16); // must be a multiple of 16
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
HRESULT hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &vscbuf);
CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", cbsize);
D3D::SetDebugObjectName((ID3D11DeviceChild*)vscbuf, "vertex shader constant buffer used to emulate the GX pipeline");
unsigned int cbsize = ROUND_UP(sizeof(VertexShaderConstants), 16); // must be a multiple of 16
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER,
D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
HRESULT hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &vscbuf);
CHECK(hr == S_OK, "Create vertex shader constant buffer (size=%u)", cbsize);
D3D::SetDebugObjectName((ID3D11DeviceChild*)vscbuf,
"vertex shader constant buffer used to emulate the GX pipeline");
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((ID3D11DeviceChild*)SimpleVertexShader, "simple vertex shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleLayout, "simple input layout");
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((ID3D11DeviceChild*)SimpleVertexShader, "simple vertex shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)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((ID3D11DeviceChild*)ClearVertexShader, "clear vertex shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearLayout, "clear 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((ID3D11DeviceChild*)ClearVertexShader, "clear vertex shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearLayout, "clear input layout");
Clear();
Clear();
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
SETSTAT(stats.numVertexShadersCreated, 0);
SETSTAT(stats.numVertexShadersAlive, 0);
SETSTAT(stats.numVertexShadersCreated, 0);
SETSTAT(stats.numVertexShadersAlive, 0);
std::string cache_filename = StringFromFormat("%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().m_strUniqueID.c_str());
VertexShaderCacheInserter inserter;
g_vs_disk_cache.OpenAndRead(cache_filename, inserter);
std::string cache_filename =
StringFromFormat("%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().m_strUniqueID.c_str());
VertexShaderCacheInserter inserter;
g_vs_disk_cache.OpenAndRead(cache_filename, inserter);
if (g_Config.bEnableShaderDebugging)
Clear();
if (g_Config.bEnableShaderDebugging)
Clear();
last_entry = nullptr;
last_entry = nullptr;
}
void VertexShaderCache::Clear()
{
for (auto& iter : vshaders)
iter.second.Destroy();
vshaders.clear();
vertex_uid_checker.Invalidate();
for (auto& iter : vshaders)
iter.second.Destroy();
vshaders.clear();
vertex_uid_checker.Invalidate();
last_entry = nullptr;
last_entry = nullptr;
}
void VertexShaderCache::Shutdown()
{
SAFE_RELEASE(vscbuf);
SAFE_RELEASE(vscbuf);
SAFE_RELEASE(SimpleVertexShader);
SAFE_RELEASE(ClearVertexShader);
SAFE_RELEASE(SimpleVertexShader);
SAFE_RELEASE(ClearVertexShader);
SAFE_RELEASE(SimpleLayout);
SAFE_RELEASE(ClearLayout);
SAFE_RELEASE(SimpleLayout);
SAFE_RELEASE(ClearLayout);
Clear();
g_vs_disk_cache.Sync();
g_vs_disk_cache.Close();
Clear();
g_vs_disk_cache.Sync();
g_vs_disk_cache.Close();
}
bool VertexShaderCache::SetShader()
{
VertexShaderUid uid = GetVertexShaderUid(API_D3D);
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GenerateVertexShaderCode(API_D3D);
vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v");
}
VertexShaderUid uid = GetVertexShaderUid(API_D3D);
if (g_ActiveConfig.bEnableShaderDebugging)
{
ShaderCode code = GenerateVertexShaderCode(API_D3D);
vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v");
}
if (last_entry)
{
if (uid == last_uid)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return (last_entry->shader != nullptr);
}
}
if (last_entry)
{
if (uid == last_uid)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return (last_entry->shader != nullptr);
}
}
last_uid = uid;
last_uid = uid;
VSCache::iterator iter = vshaders.find(uid);
if (iter != vshaders.end())
{
const VSCacheEntry &entry = iter->second;
last_entry = &entry;
VSCache::iterator iter = vshaders.find(uid);
if (iter != vshaders.end())
{
const VSCacheEntry& entry = iter->second;
last_entry = &entry;
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return (entry.shader != nullptr);
}
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return (entry.shader != nullptr);
}
ShaderCode code = GenerateVertexShaderCode(API_D3D);
ShaderCode code = GenerateVertexShaderCode(API_D3D);
D3DBlob* pbytecode = nullptr;
D3D::CompileVertexShader(code.GetBuffer(), &pbytecode);
D3DBlob* pbytecode = nullptr;
D3D::CompileVertexShader(code.GetBuffer(), &pbytecode);
if (pbytecode == nullptr)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return false;
}
g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
if (pbytecode == nullptr)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return false;
}
g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
bool success = InsertByteCode(uid, pbytecode);
pbytecode->Release();
bool success = InsertByteCode(uid, pbytecode);
pbytecode->Release();
if (g_ActiveConfig.bEnableShaderDebugging && success)
{
vshaders[uid].code = code.GetBuffer();
}
if (g_ActiveConfig.bEnableShaderDebugging && success)
{
vshaders[uid].code = code.GetBuffer();
}
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return success;
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return success;
}
bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob)
bool VertexShaderCache::InsertByteCode(const VertexShaderUid& uid, D3DBlob* bcodeblob)
{
ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob);
if (shader == nullptr)
return false;
ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob);
if (shader == nullptr)
return false;
// TODO: Somehow make the debug name a bit more specific
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache");
// TODO: Somehow make the debug name a bit more specific
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache");
// Make an entry in the table
VSCacheEntry entry;
entry.shader = shader;
entry.SetByteCode(bcodeblob);
// Make an entry in the table
VSCacheEntry entry;
entry.shader = shader;
entry.SetByteCode(bcodeblob);
vshaders[uid] = entry;
last_entry = &vshaders[uid];
vshaders[uid] = entry;
last_entry = &vshaders[uid];
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
return true;
return true;
}
} // namespace DX11

View File

@ -11,55 +11,55 @@
#include "VideoCommon/VertexShaderGen.h"
namespace DX11 {
namespace DX11
{
class VertexShaderCache
{
public:
static void Init();
static void Clear();
static void Shutdown();
static bool SetShader(); // TODO: Should be renamed to LoadShader
static void Init();
static void Clear();
static void Shutdown();
static bool SetShader(); // TODO: Should be renamed to LoadShader
static ID3D11VertexShader* GetActiveShader() { return last_entry->shader; }
static D3DBlob* GetActiveShaderBytecode() { return last_entry->bytecode; }
static ID3D11Buffer* &GetConstantBuffer();
static ID3D11VertexShader* GetActiveShader() { return last_entry->shader; }
static D3DBlob* GetActiveShaderBytecode() { return last_entry->bytecode; }
static ID3D11Buffer*& GetConstantBuffer();
static ID3D11VertexShader* GetSimpleVertexShader();
static ID3D11VertexShader* GetClearVertexShader();
static ID3D11InputLayout* GetSimpleInputLayout();
static ID3D11InputLayout* GetClearInputLayout();
static ID3D11VertexShader* GetSimpleVertexShader();
static ID3D11VertexShader* GetClearVertexShader();
static ID3D11InputLayout* GetSimpleInputLayout();
static ID3D11InputLayout* GetClearInputLayout();
static bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob);
static bool VertexShaderCache::InsertByteCode(const VertexShaderUid& uid, D3DBlob* bcodeblob);
private:
struct VSCacheEntry
{
ID3D11VertexShader* shader;
D3DBlob* bytecode; // needed to initialize the input layout
struct VSCacheEntry
{
ID3D11VertexShader* shader;
D3DBlob* bytecode; // needed to initialize the input layout
std::string code;
std::string code;
VSCacheEntry() : shader(nullptr), bytecode(nullptr) {}
void SetByteCode(D3DBlob* blob)
{
SAFE_RELEASE(bytecode);
bytecode = blob;
blob->AddRef();
}
void Destroy()
{
SAFE_RELEASE(shader);
SAFE_RELEASE(bytecode);
}
};
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
VSCacheEntry() : shader(nullptr), bytecode(nullptr) {}
void SetByteCode(D3DBlob* blob)
{
SAFE_RELEASE(bytecode);
bytecode = blob;
blob->AddRef();
}
void Destroy()
{
SAFE_RELEASE(shader);
SAFE_RELEASE(bytecode);
}
};
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
static VSCache vshaders;
static const VSCacheEntry* last_entry;
static VertexShaderUid last_uid;
static VSCache vshaders;
static const VSCacheEntry* last_entry;
static VertexShaderUid last_uid;
static UidChecker<VertexShaderUid, ShaderCode> vertex_uid_checker;
static UidChecker<VertexShaderUid, ShaderCode> vertex_uid_checker;
};
} // namespace DX11

View File

@ -9,24 +9,21 @@
namespace DX11
{
class VideoBackend : public VideoBackendBase
{
bool Initialize(void*) override;
void Shutdown() override;
bool Initialize(void*) override;
void Shutdown() override;
std::string GetName() const override;
std::string GetDisplayName() const override;
std::string GetName() const override;
std::string GetDisplayName() const override;
void Video_Prepare() override;
void Video_Cleanup() override;
void Video_Prepare() override;
void Video_Cleanup() override;
void ShowConfig(void* parent) override;
void ShowConfig(void* parent) override;
unsigned int PeekMessages() override;
unsigned int PeekMessages() override;
void* m_window_handle;
void* m_window_handle;
};
}

View File

@ -2,372 +2,366 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D/XFBEncoder.h"
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DBlob.h"
#include "VideoBackends/D3D/D3DShader.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/FramebufferManager.h"
#include "VideoBackends/D3D/Render.h"
#include "VideoBackends/D3D/XFBEncoder.h"
namespace DX11
{
union XFBEncodeParams
{
struct
{
FLOAT Width; // Width and height of encoded XFB in luma pixels
FLOAT Height;
FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture
FLOAT TexTop;
FLOAT TexRight;
FLOAT TexBottom;
FLOAT Gamma;
};
// Constant buffers must be a multiple of 16 bytes in size
u8 pad[32]; // Pad to the next multiple of 16
union XFBEncodeParams {
struct
{
FLOAT Width; // Width and height of encoded XFB in luma pixels
FLOAT Height;
FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture
FLOAT TexTop;
FLOAT TexRight;
FLOAT TexBottom;
FLOAT Gamma;
};
// Constant buffers must be a multiple of 16 bytes in size
u8 pad[32]; // Pad to the next multiple of 16
};
static const char XFB_ENCODE_VS[] =
"// dolphin-emu XFB encoder vertex shader\n"
"// dolphin-emu XFB encoder vertex shader\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match XFBEncodeParams above
"{\n"
"float Width;\n"
"float Height;\n"
"float TexLeft;\n"
"float TexTop;\n"
"float TexRight;\n"
"float TexBottom;\n"
"float Gamma;\n"
"} Params;\n"
"}\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match XFBEncodeParams above
"{\n"
"float Width;\n"
"float Height;\n"
"float TexLeft;\n"
"float TexTop;\n"
"float TexRight;\n"
"float TexBottom;\n"
"float Gamma;\n"
"} Params;\n"
"}\n"
"struct Output\n"
"{\n"
"float4 Pos : SV_Position;\n"
"float2 Coord : ENCODECOORD;\n"
"};\n"
"struct Output\n"
"{\n"
"float4 Pos : SV_Position;\n"
"float2 Coord : ENCODECOORD;\n"
"};\n"
"Output main(in float2 Pos : POSITION)\n"
"{\n"
"Output result;\n"
"result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n"
"result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n"
"return result;\n"
"}\n"
;
"Output main(in float2 Pos : POSITION)\n"
"{\n"
"Output result;\n"
"result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n"
"result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n"
"return result;\n"
"}\n";
static const char XFB_ENCODE_PS[] =
"// dolphin-emu XFB encoder pixel shader\n"
"// dolphin-emu XFB encoder pixel shader\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match XFBEncodeParams above
"{\n"
"float Width;\n"
"float Height;\n"
"float TexLeft;\n"
"float TexTop;\n"
"float TexRight;\n"
"float TexBottom;\n"
"float Gamma;\n"
"} Params;\n"
"}\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match XFBEncodeParams above
"{\n"
"float Width;\n"
"float Height;\n"
"float TexLeft;\n"
"float TexTop;\n"
"float TexRight;\n"
"float TexBottom;\n"
"float Gamma;\n"
"} Params;\n"
"}\n"
"Texture2DArray EFBTexture : register(t0);\n"
"sampler EFBSampler : register(s0);\n"
"Texture2DArray EFBTexture : register(t0);\n"
"sampler EFBSampler : register(s0);\n"
// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see
// <http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion>
"static const float3x4 RGB_TO_YCBCR = float3x4(\n"
"0.257, 0.504, 0.098, 16.0/255.0,\n"
"-0.148, -0.291, 0.439, 128.0/255.0,\n"
"0.439, -0.368, -0.071, 128.0/255.0\n"
");\n"
// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see
// <http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion>
"static const float3x4 RGB_TO_YCBCR = float3x4(\n"
"0.257, 0.504, 0.098, 16.0/255.0,\n"
"-0.148, -0.291, 0.439, 128.0/255.0,\n"
"0.439, -0.368, -0.071, 128.0/255.0\n"
");\n"
"float3 SampleEFB(float2 coord)\n"
"{\n"
"float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n"
"return EFBTexture.Sample(EFBSampler, float3(texCoord, 0.0)).rgb;\n"
"}\n"
"float3 SampleEFB(float2 coord)\n"
"{\n"
"float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), "
"float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n"
"return EFBTexture.Sample(EFBSampler, float3(texCoord, 0.0)).rgb;\n"
"}\n"
"void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : ENCODECOORD)\n"
"{\n"
// Multiplying X by 2, moves pixel centers from (x+0.5) to (2x+1) instead of (2x+0.5), so subtract 0.5 to compensate
"float2 baseCoord = Coord * float2(2,1) - float2(0.5,0);\n"
// FIXME: Shall we apply gamma here, or apply it below to the Y components?
// Be careful if you apply it to Y! The Y components are in the range (16..235) / 255.
"float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left
"float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle
"float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right
"void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : "
"ENCODECOORD)\n"
"{\n"
// Multiplying X by 2, moves pixel centers from (x+0.5) to (2x+1) instead of (2x+0.5), so
// subtract 0.5 to compensate
"float2 baseCoord = Coord * float2(2,1) - float2(0.5,0);\n"
// FIXME: Shall we apply gamma here, or apply it below to the Y components?
// Be careful if you apply it to Y! The Y components are in the range (16..235) / 255.
"float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left
"float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle
"float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right
"float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n"
"float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n"
"float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n"
"float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n"
"float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n"
"float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n"
// The Y components correspond to two EFB pixels, while the U and V are
// made from a blend of three EFB pixels.
"float y0 = yuvM.r;\n"
"float y1 = yuvR.r;\n"
"float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n"
"float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n"
// The Y components correspond to two EFB pixels, while the U and V are
// made from a blend of three EFB pixels.
"float y0 = yuvM.r;\n"
"float y1 = yuvR.r;\n"
"float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n"
"float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n"
"ocol0 = float4(y0, u0, y1, v0);\n"
"}\n"
;
"ocol0 = float4(y0, u0, y1, v0);\n"
"}\n";
static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}};
static const struct QuadVertex
{
float posX;
float posY;
} QUAD_VERTS[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
float posX;
float posY;
} QUAD_VERTS[4] = {{0, 0}, {1, 0}, {0, 1}, {1, 1}};
XFBEncoder::XFBEncoder()
: m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr), m_encodeParams(nullptr),
m_quad(nullptr), m_vShader(nullptr), m_quadLayout(nullptr), m_pShader(nullptr),
m_xfbEncodeBlendState(nullptr), m_xfbEncodeDepthState(nullptr),
m_xfbEncodeRastState(nullptr), m_efbSampler(nullptr)
{ }
: m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr), m_encodeParams(nullptr),
m_quad(nullptr), m_vShader(nullptr), m_quadLayout(nullptr), m_pShader(nullptr),
m_xfbEncodeBlendState(nullptr), m_xfbEncodeDepthState(nullptr), m_xfbEncodeRastState(nullptr),
m_efbSampler(nullptr)
{
}
void XFBEncoder::Init()
{
HRESULT hr;
HRESULT hr;
// Create output texture
// Create output texture
// The pixel shader can generate one YUYV entry per pixel. One YUYV entry
// is created for every two EFB pixels.
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH/2, MAX_XFB_HEIGHT, 1, 1,
D3D11_BIND_RENDER_TARGET);
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out);
CHECK(SUCCEEDED(hr), "create xfb encoder output texture");
D3D::SetDebugObjectName(m_out, "xfb encoder output texture");
// The pixel shader can generate one YUYV entry per pixel. One YUYV entry
// is created for every two EFB pixels.
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH / 2,
MAX_XFB_HEIGHT, 1, 1, D3D11_BIND_RENDER_TARGET);
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out);
CHECK(SUCCEEDED(hr), "create xfb encoder output texture");
D3D::SetDebugObjectName(m_out, "xfb encoder output texture");
// Create output render target view
// Create output render target view
D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out,
D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM);
hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv");
D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv");
D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(
m_out, D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM);
hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv");
D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv");
// Create output staging buffer
// Create output staging buffer
t2dd.Usage = D3D11_USAGE_STAGING;
t2dd.BindFlags = 0;
t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage);
CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer");
D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer");
t2dd.Usage = D3D11_USAGE_STAGING;
t2dd.BindFlags = 0;
t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage);
CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer");
D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer");
// Create constant buffer for uploading params to shaders
// Create constant buffer for uploading params to shaders
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams),
D3D11_BIND_CONSTANT_BUFFER);
hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams);
CHECK(SUCCEEDED(hr), "create xfb encode params buffer");
D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer");
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER);
hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams);
CHECK(SUCCEEDED(hr), "create xfb encode params buffer");
D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer");
// Create vertex quad
// Create vertex quad
bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER,
D3D11_USAGE_IMMUTABLE);
D3D11_SUBRESOURCE_DATA srd = { QUAD_VERTS, 0, 0 };
bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE);
D3D11_SUBRESOURCE_DATA srd = {QUAD_VERTS, 0, 0};
hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad);
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer");
D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer");
hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad);
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer");
D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer");
// Create vertex shader
// Create vertex shader
D3DBlob* bytecode = nullptr;
if (!D3D::CompileVertexShader(XFB_ENCODE_VS, &bytecode))
{
ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile");
return;
}
D3DBlob* bytecode = nullptr;
if (!D3D::CompileVertexShader(XFB_ENCODE_VS, &bytecode))
{
ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile");
return;
}
hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), nullptr, &m_vShader);
CHECK(SUCCEEDED(hr), "create xfb encode vertex shader");
D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader");
hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), nullptr, &m_vShader);
CHECK(SUCCEEDED(hr), "create xfb encode vertex shader");
D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader");
// Create input layout for vertex quad using bytecode from vertex shader
// Create input layout for vertex quad using bytecode from vertex shader
hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC,
sizeof(QUAD_LAYOUT_DESC)/sizeof(D3D11_INPUT_ELEMENT_DESC),
bytecode->Data(), bytecode->Size(), &m_quadLayout);
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout");
D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout");
hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC,
sizeof(QUAD_LAYOUT_DESC) / sizeof(D3D11_INPUT_ELEMENT_DESC),
bytecode->Data(), bytecode->Size(), &m_quadLayout);
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout");
D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout");
bytecode->Release();
bytecode->Release();
// Create pixel shader
// Create pixel shader
m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS);
if (!m_pShader)
{
ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile");
return;
}
D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader");
m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS);
if (!m_pShader)
{
ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile");
return;
}
D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader");
// Create blend state
// Create blend state
D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState);
CHECK(SUCCEEDED(hr), "create xfb encode blend state");
D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state");
D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState);
CHECK(SUCCEEDED(hr), "create xfb encode blend state");
D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state");
// Create depth state
// Create depth state
D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
dsd.DepthEnable = FALSE;
hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState);
CHECK(SUCCEEDED(hr), "create xfb encode depth state");
D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state");
D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
dsd.DepthEnable = FALSE;
hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState);
CHECK(SUCCEEDED(hr), "create xfb encode depth state");
D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state");
// Create rasterizer state
// Create rasterizer state
D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
rd.CullMode = D3D11_CULL_NONE;
rd.DepthClipEnable = FALSE;
hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState);
CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state");
D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state");
D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
rd.CullMode = D3D11_CULL_NONE;
rd.DepthClipEnable = FALSE;
hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState);
CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state");
D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state");
// Create EFB texture sampler
// Create EFB texture sampler
D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
sd.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler);
CHECK(SUCCEEDED(hr), "create xfb encode texture sampler");
D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler");
D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
sd.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler);
CHECK(SUCCEEDED(hr), "create xfb encode texture sampler");
D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler");
}
void XFBEncoder::Shutdown()
{
SAFE_RELEASE(m_efbSampler);
SAFE_RELEASE(m_xfbEncodeRastState);
SAFE_RELEASE(m_xfbEncodeDepthState);
SAFE_RELEASE(m_xfbEncodeBlendState);
SAFE_RELEASE(m_pShader);
SAFE_RELEASE(m_quadLayout);
SAFE_RELEASE(m_vShader);
SAFE_RELEASE(m_quad);
SAFE_RELEASE(m_encodeParams);
SAFE_RELEASE(m_outStage);
SAFE_RELEASE(m_outRTV);
SAFE_RELEASE(m_out);
SAFE_RELEASE(m_efbSampler);
SAFE_RELEASE(m_xfbEncodeRastState);
SAFE_RELEASE(m_xfbEncodeDepthState);
SAFE_RELEASE(m_xfbEncodeBlendState);
SAFE_RELEASE(m_pShader);
SAFE_RELEASE(m_quadLayout);
SAFE_RELEASE(m_vShader);
SAFE_RELEASE(m_quad);
SAFE_RELEASE(m_encodeParams);
SAFE_RELEASE(m_outStage);
SAFE_RELEASE(m_outRTV);
SAFE_RELEASE(m_out);
}
void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma)
{
HRESULT hr;
HRESULT hr;
// Reset API
// Reset API
g_renderer->ResetAPIState();
g_renderer->ResetAPIState();
// Set up all the state for XFB encoding
// Set up all the state for XFB encoding
D3D::stateman->SetPixelShader(m_pShader);
D3D::stateman->SetVertexShader(m_vShader);
D3D::stateman->SetGeometryShader(nullptr);
D3D::stateman->SetPixelShader(m_pShader);
D3D::stateman->SetVertexShader(m_vShader);
D3D::stateman->SetGeometryShader(nullptr);
D3D::stateman->PushBlendState(m_xfbEncodeBlendState);
D3D::stateman->PushDepthState(m_xfbEncodeDepthState);
D3D::stateman->PushRasterizerState(m_xfbEncodeRastState);
D3D::stateman->PushBlendState(m_xfbEncodeBlendState);
D3D::stateman->PushDepthState(m_xfbEncodeDepthState);
D3D::stateman->PushRasterizerState(m_xfbEncodeRastState);
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width/2), FLOAT(height));
D3D::context->RSSetViewports(1, &vp);
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width / 2), FLOAT(height));
D3D::context->RSSetViewports(1, &vp);
D3D::stateman->SetInputLayout(m_quadLayout);
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
UINT stride = sizeof(QuadVertex);
UINT offset = 0;
D3D::stateman->SetVertexBuffer(m_quad, stride, offset);
D3D::stateman->SetInputLayout(m_quadLayout);
D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
UINT stride = sizeof(QuadVertex);
UINT offset = 0;
D3D::stateman->SetVertexBuffer(m_quad, stride, offset);
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect);
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect);
XFBEncodeParams params = { 0 };
params.Width = FLOAT(width);
params.Height = FLOAT(height);
params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetTargetWidth();
params.TexTop = FLOAT(targetRect.top) / g_renderer->GetTargetHeight();
params.TexRight = FLOAT(targetRect.right) / g_renderer->GetTargetWidth();
params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetTargetHeight();
params.Gamma = gamma;
D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, &params, 0, 0);
XFBEncodeParams params = {0};
params.Width = FLOAT(width);
params.Height = FLOAT(height);
params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetTargetWidth();
params.TexTop = FLOAT(targetRect.top) / g_renderer->GetTargetHeight();
params.TexRight = FLOAT(targetRect.right) / g_renderer->GetTargetWidth();
params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetTargetHeight();
params.Gamma = gamma;
D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, &params, 0, 0);
D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr);
D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr);
ID3D11ShaderResourceView* pEFB = FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
ID3D11ShaderResourceView* pEFB = FramebufferManager::GetResolvedEFBColorTexture()->GetSRV();
D3D::stateman->SetVertexConstants(m_encodeParams);
D3D::stateman->SetPixelConstants(m_encodeParams);
D3D::stateman->SetTexture(0, pEFB);
D3D::stateman->SetSampler(0, m_efbSampler);
D3D::stateman->SetVertexConstants(m_encodeParams);
D3D::stateman->SetPixelConstants(m_encodeParams);
D3D::stateman->SetTexture(0, pEFB);
D3D::stateman->SetSampler(0, m_efbSampler);
// Encode!
// Encode!
D3D::stateman->Apply();
D3D::context->Draw(4, 0);
D3D::stateman->Apply();
D3D::context->Draw(4, 0);
// Copy to staging buffer
// Copy to staging buffer
D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width/2, height, 1);
D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox);
D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width / 2, height, 1);
D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox);
// Clean up state
// Clean up state
D3D::context->OMSetRenderTargets(0, nullptr, nullptr);
D3D::context->OMSetRenderTargets(0, nullptr, nullptr);
D3D::stateman->SetSampler(0, nullptr);
D3D::stateman->SetTexture(0, nullptr);
D3D::stateman->SetPixelConstants(nullptr);
D3D::stateman->SetVertexConstants(nullptr);
D3D::stateman->SetSampler(0, nullptr);
D3D::stateman->SetTexture(0, nullptr);
D3D::stateman->SetPixelConstants(nullptr);
D3D::stateman->SetVertexConstants(nullptr);
D3D::stateman->SetPixelShader(nullptr);
D3D::stateman->SetVertexShader(nullptr);
D3D::stateman->SetPixelShader(nullptr);
D3D::stateman->SetVertexShader(nullptr);
D3D::stateman->PopRasterizerState();
D3D::stateman->PopDepthState();
D3D::stateman->PopBlendState();
D3D::stateman->PopRasterizerState();
D3D::stateman->PopDepthState();
D3D::stateman->PopBlendState();
// Transfer staging buffer to GameCube/Wii RAM
// Transfer staging buffer to GameCube/Wii RAM
D3D11_MAPPED_SUBRESOURCE map = { 0 };
hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
CHECK(SUCCEEDED(hr), "map staging buffer");
D3D11_MAPPED_SUBRESOURCE map = {0};
hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
CHECK(SUCCEEDED(hr), "map staging buffer");
u8* src = (u8*)map.pData;
for (unsigned int y = 0; y < height; ++y)
{
memcpy(dst, src, 2*width);
dst += bpmem.copyMipMapStrideChannels*32;
src += map.RowPitch;
}
u8* src = (u8*)map.pData;
for (unsigned int y = 0; y < height; ++y)
{
memcpy(dst, src, 2 * width);
dst += bpmem.copyMipMapStrideChannels * 32;
src += map.RowPitch;
}
D3D::context->Unmap(m_outStage, 0);
D3D::context->Unmap(m_outStage, 0);
// Restore API
g_renderer->RestoreAPIState();
D3D::stateman->Apply(); // force unbind efb texture as shader resource
D3D::context->OMSetRenderTargets(1,
&FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
// Restore API
g_renderer->RestoreAPIState();
D3D::stateman->Apply(); // force unbind efb texture as shader resource
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
}
}

View File

@ -19,34 +19,28 @@ struct ID3D11SamplerState;
namespace DX11
{
class XFBEncoder
{
public:
XFBEncoder();
XFBEncoder();
void Init();
void Shutdown();
void Init();
void Shutdown();
void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma);
void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma);
private:
ID3D11Texture2D* m_out;
ID3D11RenderTargetView* m_outRTV;
ID3D11Texture2D* m_outStage;
ID3D11Buffer* m_encodeParams;
ID3D11Buffer* m_quad;
ID3D11VertexShader* m_vShader;
ID3D11InputLayout* m_quadLayout;
ID3D11PixelShader* m_pShader;
ID3D11BlendState* m_xfbEncodeBlendState;
ID3D11DepthStencilState* m_xfbEncodeDepthState;
ID3D11RasterizerState* m_xfbEncodeRastState;
ID3D11SamplerState* m_efbSampler;
ID3D11Texture2D* m_out;
ID3D11RenderTargetView* m_outRTV;
ID3D11Texture2D* m_outStage;
ID3D11Buffer* m_encodeParams;
ID3D11Buffer* m_quad;
ID3D11VertexShader* m_vShader;
ID3D11InputLayout* m_quadLayout;
ID3D11PixelShader* m_pShader;
ID3D11BlendState* m_xfbEncodeBlendState;
ID3D11DepthStencilState* m_xfbEncodeDepthState;
ID3D11RasterizerState* m_xfbEncodeRastState;
ID3D11SamplerState* m_efbSampler;
};
}

View File

@ -38,198 +38,198 @@
namespace DX11
{
unsigned int VideoBackend::PeekMessages()
{
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return FALSE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return FALSE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
}
std::string VideoBackend::GetName() const
{
return "D3D";
return "D3D";
}
std::string VideoBackend::GetDisplayName() const
{
return "Direct3D 11";
return "Direct3D 11";
}
void InitBackendInfo()
{
HRESULT hr = DX11::D3D::LoadDXGI();
if (SUCCEEDED(hr)) hr = DX11::D3D::LoadD3D();
if (FAILED(hr))
{
DX11::D3D::UnloadDXGI();
return;
}
HRESULT hr = DX11::D3D::LoadDXGI();
if (SUCCEEDED(hr))
hr = DX11::D3D::LoadD3D();
if (FAILED(hr))
{
DX11::D3D::UnloadDXGI();
return;
}
g_Config.backend_info.APIType = API_D3D;
g_Config.backend_info.bSupportsExclusiveFullscreen = true;
g_Config.backend_info.bSupportsDualSourceBlend = true;
g_Config.backend_info.bSupportsPrimitiveRestart = true;
g_Config.backend_info.bSupportsOversizedViewports = false;
g_Config.backend_info.bSupportsGeometryShaders = true;
g_Config.backend_info.bSupports3DVision = true;
g_Config.backend_info.bSupportsPostProcessing = false;
g_Config.backend_info.bSupportsPaletteConversion = true;
g_Config.backend_info.bSupportsClipControl = true;
g_Config.backend_info.APIType = API_D3D;
g_Config.backend_info.bSupportsExclusiveFullscreen = true;
g_Config.backend_info.bSupportsDualSourceBlend = true;
g_Config.backend_info.bSupportsPrimitiveRestart = true;
g_Config.backend_info.bSupportsOversizedViewports = false;
g_Config.backend_info.bSupportsGeometryShaders = true;
g_Config.backend_info.bSupports3DVision = true;
g_Config.backend_info.bSupportsPostProcessing = false;
g_Config.backend_info.bSupportsPaletteConversion = true;
g_Config.backend_info.bSupportsClipControl = true;
IDXGIFactory* factory;
IDXGIAdapter* ad;
hr = DX11::PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
if (FAILED(hr))
PanicAlert("Failed to create IDXGIFactory object");
IDXGIFactory* factory;
IDXGIAdapter* ad;
hr = DX11::PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
if (FAILED(hr))
PanicAlert("Failed to create IDXGIFactory object");
// adapters
g_Config.backend_info.Adapters.clear();
g_Config.backend_info.AAModes.clear();
while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != DXGI_ERROR_NOT_FOUND)
{
const size_t adapter_index = g_Config.backend_info.Adapters.size();
// adapters
g_Config.backend_info.Adapters.clear();
g_Config.backend_info.AAModes.clear();
while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) !=
DXGI_ERROR_NOT_FOUND)
{
const size_t adapter_index = g_Config.backend_info.Adapters.size();
DXGI_ADAPTER_DESC desc;
ad->GetDesc(&desc);
DXGI_ADAPTER_DESC desc;
ad->GetDesc(&desc);
// TODO: These don't get updated on adapter change, yet
if (adapter_index == g_Config.iAdapter)
{
std::string samples;
std::vector<DXGI_SAMPLE_DESC> modes = DX11::D3D::EnumAAModes(ad);
// First iteration will be 1. This equals no AA.
for (unsigned int i = 0; i < modes.size(); ++i)
{
g_Config.backend_info.AAModes.push_back(modes[i].Count);
}
// TODO: These don't get updated on adapter change, yet
if (adapter_index == g_Config.iAdapter)
{
std::string samples;
std::vector<DXGI_SAMPLE_DESC> modes = DX11::D3D::EnumAAModes(ad);
// First iteration will be 1. This equals no AA.
for (unsigned int i = 0; i < modes.size(); ++i)
{
g_Config.backend_info.AAModes.push_back(modes[i].Count);
}
bool shader_model_5_supported = (DX11::D3D::GetFeatureLevel(ad) >= D3D_FEATURE_LEVEL_11_0);
bool shader_model_5_supported = (DX11::D3D::GetFeatureLevel(ad) >= D3D_FEATURE_LEVEL_11_0);
// Requires the earlydepthstencil attribute (only available in shader model 5)
g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported;
// Requires the earlydepthstencil attribute (only available in shader model 5)
g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported;
// Requires full UAV functionality (only available in shader model 5)
g_Config.backend_info.bSupportsBBox = shader_model_5_supported;
// Requires full UAV functionality (only available in shader model 5)
g_Config.backend_info.bSupportsBBox = shader_model_5_supported;
// Requires the instance attribute (only available in shader model 5)
g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported;
// Requires the instance attribute (only available in shader model 5)
g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported;
// Sample shading requires shader model 5
g_Config.backend_info.bSupportsSSAA = shader_model_5_supported;
}
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));
ad->Release();
}
factory->Release();
// Sample shading requires shader model 5
g_Config.backend_info.bSupportsSSAA = shader_model_5_supported;
}
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));
ad->Release();
}
factory->Release();
// Clear ppshaders string vector
g_Config.backend_info.PPShaders.clear();
g_Config.backend_info.AnaglyphShaders.clear();
// Clear ppshaders string vector
g_Config.backend_info.PPShaders.clear();
g_Config.backend_info.AnaglyphShaders.clear();
DX11::D3D::UnloadDXGI();
DX11::D3D::UnloadD3D();
DX11::D3D::UnloadDXGI();
DX11::D3D::UnloadD3D();
}
void VideoBackend::ShowConfig(void *hParent)
void VideoBackend::ShowConfig(void* hParent)
{
InitBackendInfo();
Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_dx11");
InitBackendInfo();
Host_ShowVideoConfig(hParent, GetDisplayName(), "gfx_dx11");
}
bool VideoBackend::Initialize(void *window_handle)
bool VideoBackend::Initialize(void* window_handle)
{
if (window_handle == nullptr)
return false;
if (window_handle == nullptr)
return false;
InitializeShared();
InitBackendInfo();
InitializeShared();
InitBackendInfo();
frameCount = 0;
frameCount = 0;
if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"))
g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
else
g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_dx11.ini");
if (File::Exists(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini"))
g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
else
g_Config.Load(File::GetUserPath(D_CONFIG_IDX) + "gfx_dx11.ini");
g_Config.GameIniLoad();
g_Config.UpdateProjectionHack();
g_Config.VerifyValidity();
UpdateActiveConfig();
g_Config.GameIniLoad();
g_Config.UpdateProjectionHack();
g_Config.VerifyValidity();
UpdateActiveConfig();
m_window_handle = window_handle;
m_initialized = true;
m_window_handle = window_handle;
m_initialized = true;
return true;
return true;
}
void VideoBackend::Video_Prepare()
{
// internal interfaces
g_renderer = std::make_unique<Renderer>(m_window_handle);
g_texture_cache = std::make_unique<TextureCache>();
g_vertex_manager = std::make_unique<VertexManager>();
g_perf_query = std::make_unique<PerfQuery>();
VertexShaderCache::Init();
PixelShaderCache::Init();
GeometryShaderCache::Init();
D3D::InitUtils();
// internal interfaces
g_renderer = std::make_unique<Renderer>(m_window_handle);
g_texture_cache = std::make_unique<TextureCache>();
g_vertex_manager = std::make_unique<VertexManager>();
g_perf_query = std::make_unique<PerfQuery>();
VertexShaderCache::Init();
PixelShaderCache::Init();
GeometryShaderCache::Init();
D3D::InitUtils();
// VideoCommon
BPInit();
Fifo::Init();
IndexGenerator::Init();
VertexLoaderManager::Init();
OpcodeDecoder::Init();
VertexShaderManager::Init();
PixelShaderManager::Init();
GeometryShaderManager::Init();
CommandProcessor::Init();
PixelEngine::Init();
BBox::Init();
// VideoCommon
BPInit();
Fifo::Init();
IndexGenerator::Init();
VertexLoaderManager::Init();
OpcodeDecoder::Init();
VertexShaderManager::Init();
PixelShaderManager::Init();
GeometryShaderManager::Init();
CommandProcessor::Init();
PixelEngine::Init();
BBox::Init();
// Tell the host that the window is ready
Host_Message(WM_USER_CREATE);
// Tell the host that the window is ready
Host_Message(WM_USER_CREATE);
}
void VideoBackend::Shutdown()
{
m_initialized = false;
m_initialized = false;
// TODO: should be in Video_Cleanup
if (g_renderer)
{
// VideoCommon
Fifo::Shutdown();
CommandProcessor::Shutdown();
GeometryShaderManager::Shutdown();
PixelShaderManager::Shutdown();
VertexShaderManager::Shutdown();
OpcodeDecoder::Shutdown();
VertexLoaderManager::Shutdown();
// TODO: should be in Video_Cleanup
if (g_renderer)
{
// VideoCommon
Fifo::Shutdown();
CommandProcessor::Shutdown();
GeometryShaderManager::Shutdown();
PixelShaderManager::Shutdown();
VertexShaderManager::Shutdown();
OpcodeDecoder::Shutdown();
VertexLoaderManager::Shutdown();
// internal interfaces
D3D::ShutdownUtils();
PixelShaderCache::Shutdown();
VertexShaderCache::Shutdown();
GeometryShaderCache::Shutdown();
BBox::Shutdown();
// internal interfaces
D3D::ShutdownUtils();
PixelShaderCache::Shutdown();
VertexShaderCache::Shutdown();
GeometryShaderCache::Shutdown();
BBox::Shutdown();
g_perf_query.reset();
g_vertex_manager.reset();
g_texture_cache.reset();
g_renderer.reset();
}
g_perf_query.reset();
g_vertex_manager.reset();
g_texture_cache.reset();
g_renderer.reset();
}
}
void VideoBackend::Video_Cleanup()
{
}
}