2017-02-27 10:09:21 +01:00
# include "ppsspp_config.h"
2016-12-23 09:34:24 +01:00
# include "Common/CommonWindows.h"
# include <d3d11.h>
2018-04-15 10:53:07 +02:00
# include <WinError.h>
2016-12-23 09:34:24 +01:00
2020-08-15 12:25:39 +02:00
# include "Common/Log.h"
2020-10-04 10:10:55 +02:00
# include "Common/System/Display.h"
2020-10-01 13:05:04 +02:00
# include "Common/Data/Encoding/Utf8.h"
# include "Common/Data/Text/I18n.h"
2016-12-23 09:34:24 +01:00
# include "Core/Config.h"
2018-06-16 18:42:31 -07:00
# include "Core/ConfigValues.h"
2017-12-26 15:59:02 -08:00
# include "Core/System.h"
2016-12-23 09:34:24 +01:00
# include "Windows/GPU/D3D11Context.h"
# include "Windows/W32Util/Misc.h"
2020-10-04 23:24:14 +02:00
# include "Common/GPU/thin3d.h"
# include "Common/GPU/thin3d_create.h"
# include "Common/GPU/D3D11/D3D11Loader.h"
2017-02-07 11:44:44 +01:00
2018-03-23 03:18:13 +01:00
# ifdef __MINGW32__
# undef __uuidof
# define __uuidof(type) IID_##type
# endif
2018-04-15 10:53:07 +02:00
# ifndef DXGI_ERROR_NOT_FOUND
# define _FACDXGI 0x87a
# define MAKE_DXGI_HRESULT(code) MAKE_HRESULT(1, _FACDXGI, code)
# define DXGI_ERROR_NOT_FOUND MAKE_DXGI_HRESULT(2)
# endif
2017-03-03 22:48:05 +01:00
# if PPSSPP_PLATFORM(UWP)
# error This file should not be compiled for UWP.
# endif
2018-04-15 10:53:07 +02:00
HRESULT D3D11Context : : CreateTheDevice ( IDXGIAdapter * adapter ) {
2016-12-23 09:34:24 +01:00
bool windowed = true ;
2019-06-24 10:30:32 +02:00
// D3D11 has no need for display rotation.
2023-02-25 13:09:44 +01:00
g_display . rotation = DisplayRotation : : ROTATE_0 ;
g_display . rot_matrix . setIdentity ( ) ;
2020-08-29 08:45:50 -07:00
# if defined(_DEBUG) && !PPSSPP_ARCH(ARM) && !PPSSPP_ARCH(ARM64)
2017-02-23 10:40:55 +01:00
UINT createDeviceFlags = D3D11_CREATE_DEVICE_DEBUG ;
# else
UINT createDeviceFlags = 0 ;
2016-12-23 09:34:24 +01:00
# endif
2017-02-07 11:44:44 +01:00
static const D3D_FEATURE_LEVEL featureLevels [ ] = {
2017-03-05 11:05:36 +01:00
D3D_FEATURE_LEVEL_12_1 ,
D3D_FEATURE_LEVEL_12_0 ,
2017-02-07 11:44:44 +01:00
D3D_FEATURE_LEVEL_11_1 ,
2016-12-23 09:34:24 +01:00
D3D_FEATURE_LEVEL_11_0 ,
D3D_FEATURE_LEVEL_10_1 ,
D3D_FEATURE_LEVEL_10_0 ,
} ;
2017-02-23 10:40:55 +01:00
const UINT numFeatureLevels = ARRAYSIZE ( featureLevels ) ;
2016-12-23 09:34:24 +01:00
2017-02-17 19:51:05 +01:00
HRESULT hr = S_OK ;
2018-04-15 10:53:07 +02:00
D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_UNKNOWN ;
hr = ptr_D3D11CreateDevice ( adapter , driverType , nullptr , createDeviceFlags , ( D3D_FEATURE_LEVEL * ) featureLevels , numFeatureLevels ,
D3D11_SDK_VERSION , & device_ , & featureLevel_ , & context_ ) ;
if ( hr = = E_INVALIDARG ) {
// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
hr = ptr_D3D11CreateDevice ( adapter , driverType , nullptr , createDeviceFlags , ( D3D_FEATURE_LEVEL * ) & featureLevels [ 3 ] , numFeatureLevels - 3 ,
2016-12-23 09:34:24 +01:00
D3D11_SDK_VERSION , & device_ , & featureLevel_ , & context_ ) ;
}
2017-02-23 10:40:55 +01:00
return hr ;
}
bool D3D11Context : : Init ( HINSTANCE hInst , HWND wnd , std : : string * error_message ) {
hWnd_ = wnd ;
LoadD3D11Error result = LoadD3D11 ( ) ;
HRESULT hr = E_FAIL ;
2018-04-15 10:53:07 +02:00
std : : vector < std : : string > adapterNames ;
2018-09-30 00:53:21 -07:00
std : : string chosenAdapterName ;
2017-02-23 10:40:55 +01:00
if ( result = = LoadD3D11Error : : SUCCESS ) {
2018-04-15 10:53:07 +02:00
std : : vector < IDXGIAdapter * > adapters ;
int chosenAdapter = 0 ;
2019-05-16 00:36:14 +02:00
IDXGIFactory * pFactory = nullptr ;
2018-04-15 10:53:07 +02:00
2019-05-15 22:55:24 +02:00
hr = ptr_CreateDXGIFactory ( __uuidof ( IDXGIFactory ) , ( void * * ) & pFactory ) ;
if ( SUCCEEDED ( hr ) ) {
IDXGIAdapter * pAdapter ;
for ( UINT i = 0 ; pFactory - > EnumAdapters ( i , & pAdapter ) ! = DXGI_ERROR_NOT_FOUND ; i + + ) {
adapters . push_back ( pAdapter ) ;
DXGI_ADAPTER_DESC desc ;
pAdapter - > GetDesc ( & desc ) ;
std : : string str = ConvertWStringToUTF8 ( desc . Description ) ;
adapterNames . push_back ( str ) ;
if ( str = = g_Config . sD3D11Device ) {
chosenAdapter = i ;
}
2018-04-15 10:53:07 +02:00
}
2019-05-15 22:58:45 +02:00
if ( ! adapters . empty ( ) ) {
chosenAdapterName = adapterNames [ chosenAdapter ] ;
hr = CreateTheDevice ( adapters [ chosenAdapter ] ) ;
for ( int i = 0 ; i < ( int ) adapters . size ( ) ; i + + ) {
adapters [ i ] - > Release ( ) ;
}
} else {
// No adapters found. Trip the error path below.
hr = E_FAIL ;
2019-05-15 22:55:24 +02:00
}
2019-05-16 00:36:14 +02:00
pFactory - > Release ( ) ;
2018-04-15 10:53:07 +02:00
}
2017-02-23 10:40:55 +01:00
}
2017-02-17 19:51:05 +01:00
if ( FAILED ( hr ) ) {
const char * defaultError = " Your GPU does not appear to support Direct3D 11. \n \n Would you like to try again using Direct3D 9 instead? " ;
2023-04-06 00:34:50 +02:00
auto err = GetI18NCategory ( I18NCat : : ERRORS ) ;
2017-02-17 19:51:05 +01:00
2017-02-23 10:40:55 +01:00
std : : wstring error ;
if ( result = = LoadD3D11Error : : FAIL_NO_COMPILER ) {
error = ConvertUTF8ToWString ( err - > T ( " D3D11CompilerMissing " , " D3DCompiler_47.dll not found. Please install. Or press Yes to try again using Direct3D9 instead. " ) ) ;
} else if ( result = = LoadD3D11Error : : FAIL_NO_D3D11 ) {
error = ConvertUTF8ToWString ( err - > T ( " D3D11Missing " , " Your operating system version does not include D3D11. Please run Windows Update. \n \n Press Yes to try again using Direct3D9 instead. " ) ) ;
}
error = ConvertUTF8ToWString ( err - > T ( " D3D11NotSupported " , defaultError ) ) ;
2017-02-17 19:51:05 +01:00
std : : wstring title = ConvertUTF8ToWString ( err - > T ( " D3D11InitializationError " , " Direct3D 11 initialization error " ) ) ;
bool yes = IDYES = = MessageBox ( hWnd_ , error . c_str ( ) , title . c_str ( ) , MB_ICONERROR | MB_YESNO ) ;
if ( yes ) {
2019-02-23 10:49:49 +01:00
// Change the config to D3D9 and restart.
2017-12-26 15:55:24 -08:00
g_Config . iGPUBackend = ( int ) GPUBackend : : DIRECT3D9 ;
2018-09-01 13:57:20 -07:00
g_Config . sFailedGPUBackends . clear ( ) ;
2019-02-23 10:49:49 +01:00
g_Config . Save ( " save_d3d9_fallback " ) ;
2017-02-17 19:51:05 +01:00
W32Util : : ExitAndRestart ( ) ;
}
2016-12-23 09:34:24 +01:00
return false ;
2017-02-17 19:51:05 +01:00
}
2016-12-23 09:34:24 +01:00
2017-02-18 01:54:28 +01:00
if ( FAILED ( device_ - > QueryInterface ( __uuidof ( ID3D11Device1 ) , ( void * * ) & device1_ ) ) ) {
device1_ = nullptr ;
}
if ( FAILED ( context_ - > QueryInterface ( __uuidof ( ID3D11DeviceContext1 ) , ( void * * ) & context1_ ) ) ) {
context1_ = nullptr ;
}
2017-02-10 00:01:34 +01:00
# ifdef _DEBUG
2017-02-10 00:30:42 +01:00
if ( SUCCEEDED ( device_ - > QueryInterface ( __uuidof ( ID3D11Debug ) , ( void * * ) & d3dDebug_ ) ) ) {
2017-02-10 11:25:24 +01:00
if ( SUCCEEDED ( d3dDebug_ - > QueryInterface ( __uuidof ( ID3D11InfoQueue ) , ( void * * ) & d3dInfoQueue_ ) ) ) {
d3dInfoQueue_ - > SetBreakOnSeverity ( D3D11_MESSAGE_SEVERITY_CORRUPTION , true ) ;
d3dInfoQueue_ - > SetBreakOnSeverity ( D3D11_MESSAGE_SEVERITY_ERROR , true ) ;
2017-02-17 14:30:42 +01:00
d3dInfoQueue_ - > SetBreakOnSeverity ( D3D11_MESSAGE_SEVERITY_WARNING , true ) ;
2017-02-10 00:01:34 +01:00
}
}
# endif
2017-02-27 10:09:21 +01:00
int width ;
int height ;
2023-08-10 10:28:25 +02:00
W32Util : : GetWindowRes ( hWnd_ , & width , & height ) ;
2017-02-27 10:09:21 +01:00
// Obtain DXGI factory from device (since we used nullptr for pAdapter above)
2023-08-06 16:03:15 +02:00
IDXGIFactory1 * dxgiFactory = nullptr ;
2023-08-04 11:53:51 +02:00
IDXGIDevice * dxgiDevice = nullptr ;
2023-08-06 16:03:15 +02:00
IDXGIAdapter * adapter = nullptr ;
2017-02-27 10:09:21 +01:00
hr = device_ - > QueryInterface ( __uuidof ( IDXGIDevice ) , reinterpret_cast < void * * > ( & dxgiDevice ) ) ;
if ( SUCCEEDED ( hr ) ) {
hr = dxgiDevice - > GetAdapter ( & adapter ) ;
if ( SUCCEEDED ( hr ) ) {
hr = adapter - > GetParent ( __uuidof ( IDXGIFactory1 ) , reinterpret_cast < void * * > ( & dxgiFactory ) ) ;
DXGI_ADAPTER_DESC desc ;
adapter - > GetDesc ( & desc ) ;
adapter - > Release ( ) ;
}
dxgiDevice - > Release ( ) ;
}
// DirectX 11.0 systems
DXGI_SWAP_CHAIN_DESC sd ;
ZeroMemory ( & sd , sizeof ( sd ) ) ;
sd . BufferCount = 1 ;
sd . BufferDesc . Width = width ;
sd . BufferDesc . Height = height ;
sd . BufferDesc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
sd . BufferDesc . RefreshRate . Numerator = 60 ;
sd . BufferDesc . RefreshRate . Denominator = 1 ;
sd . BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT ;
sd . OutputWindow = hWnd_ ;
sd . SampleDesc . Count = 1 ;
sd . SampleDesc . Quality = 0 ;
sd . Windowed = TRUE ;
hr = dxgiFactory - > CreateSwapChain ( device_ , & sd , & swapChain_ ) ;
dxgiFactory - > MakeWindowAssociation ( hWnd_ , DXGI_MWA_NO_ALT_ENTER ) ;
dxgiFactory - > Release ( ) ;
2023-08-11 00:31:47 +02:00
draw_ = Draw : : T3DCreateD3D11Context ( device_ , context_ , device1_ , context1_ , swapChain_ , featureLevel_ , hWnd_ , adapterNames , g_Config . iInflightFrames ) ;
SetGPUBackend ( GPUBackend : : DIRECT3D11 , chosenAdapterName ) ;
bool success = draw_ - > CreatePresets ( ) ; // If we can run D3D11, there's a compiler installed. I think.
_assert_msg_ ( success , " Failed to compile preset shaders " ) ;
2017-02-27 10:09:21 +01:00
GotBackbuffer ( ) ;
2016-12-23 09:34:24 +01:00
return true ;
}
2017-02-27 10:09:21 +01:00
void D3D11Context : : LostBackbuffer ( ) {
draw_ - > HandleEvent ( Draw : : Event : : LOST_BACKBUFFER , width , height , nullptr ) ;
bbRenderTargetTex_ - > Release ( ) ;
bbRenderTargetTex_ = nullptr ;
bbRenderTargetView_ - > Release ( ) ;
bbRenderTargetView_ = nullptr ;
}
void D3D11Context : : GotBackbuffer ( ) {
// Create a render target view
ID3D11Texture2D * pBackBuffer = nullptr ;
HRESULT hr = swapChain_ - > GetBuffer ( 0 , __uuidof ( ID3D11Texture2D ) , reinterpret_cast < void * * > ( & bbRenderTargetTex_ ) ) ;
if ( FAILED ( hr ) )
return ;
D3D11_TEXTURE2D_DESC bbDesc { } ;
bbRenderTargetTex_ - > GetDesc ( & bbDesc ) ;
width = bbDesc . Width ;
height = bbDesc . Height ;
hr = device_ - > CreateRenderTargetView ( bbRenderTargetTex_ , nullptr , & bbRenderTargetView_ ) ;
if ( FAILED ( hr ) )
return ;
2017-03-05 20:30:39 +01:00
draw_ - > HandleEvent ( Draw : : Event : : GOT_BACKBUFFER , width , height , bbRenderTargetView_ , bbRenderTargetTex_ ) ;
2017-02-27 10:09:21 +01:00
}
2016-12-23 09:34:24 +01:00
void D3D11Context : : Resize ( ) {
2017-02-27 10:09:21 +01:00
LostBackbuffer ( ) ;
int width ;
int height ;
2023-08-10 10:28:25 +02:00
W32Util : : GetWindowRes ( hWnd_ , & width , & height ) ;
2017-02-27 10:09:21 +01:00
swapChain_ - > ResizeBuffers ( 0 , width , height , DXGI_FORMAT_UNKNOWN , 0 ) ;
GotBackbuffer ( ) ;
2016-12-23 09:34:24 +01:00
}
void D3D11Context : : Shutdown ( ) {
2017-02-27 10:09:21 +01:00
LostBackbuffer ( ) ;
2017-02-10 14:41:32 +01:00
delete draw_ ;
draw_ = nullptr ;
2017-04-27 20:04:30 -07:00
swapChain_ - > Release ( ) ;
swapChain_ = nullptr ;
if ( context1_ )
context1_ - > Release ( ) ;
if ( device1_ )
device1_ - > Release ( ) ;
device1_ = nullptr ;
device_ - > Release ( ) ;
device_ = nullptr ;
2017-02-10 14:41:32 +01:00
context_ - > ClearState ( ) ;
context_ - > Flush ( ) ;
2017-04-27 20:04:30 -07:00
context_ - > Release ( ) ;
context_ = nullptr ;
2017-02-10 14:41:32 +01:00
2017-02-10 11:25:24 +01:00
# ifdef _DEBUG
2021-01-02 20:47:21 -08:00
if ( d3dInfoQueue_ ) {
d3dInfoQueue_ - > SetBreakOnSeverity ( D3D11_MESSAGE_SEVERITY_CORRUPTION , false ) ;
d3dInfoQueue_ - > SetBreakOnSeverity ( D3D11_MESSAGE_SEVERITY_ERROR , false ) ;
d3dInfoQueue_ - > SetBreakOnSeverity ( D3D11_MESSAGE_SEVERITY_WARNING , false ) ;
}
if ( d3dDebug_ ) {
d3dDebug_ - > ReportLiveDeviceObjects ( D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL ) ;
d3dDebug_ - > Release ( ) ;
d3dDebug_ = nullptr ;
}
if ( d3dInfoQueue_ ) {
d3dInfoQueue_ - > Release ( ) ;
d3dInfoQueue_ = nullptr ;
}
2017-02-12 12:12:15 +01:00
# endif
2017-02-06 11:20:27 +01:00
2016-12-23 09:34:24 +01:00
hWnd_ = nullptr ;
2017-02-23 10:40:55 +01:00
UnloadD3D11 ( ) ;
2017-04-27 20:04:30 -07:00
}