mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 06:39:46 -06:00
Reformat all the things. Have fun with merge conflicts.
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, ¶ms, 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, ¶ms, 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
@ -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
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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, ¶ms, 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, ¶ms, 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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];
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -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, ¶ms, 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, ¶ms, 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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user