2010-06-13 19:50:06 +00:00
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
# include "D3DBase.h"
# include "D3DTexture.h"
# include "D3DShader.h"
# include "D3Dcompiler.h"
# include "VideoConfig.h"
# include "Render.h"
# include "XFStructs.h"
2010-06-27 14:04:49 +00:00
# include "StringUtil.h"
2010-06-13 19:50:06 +00:00
2010-06-27 14:04:49 +00:00
HINSTANCE hD3DXDll = NULL ;
2010-06-27 16:08:54 +00:00
D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory = NULL ;
2010-06-27 14:04:49 +00:00
D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture = NULL ;
D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA = NULL ;
D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW = NULL ;
2010-06-13 19:50:06 +00:00
namespace D3D
{
ID3D11Device * device = NULL ;
ID3D11DeviceContext * context = NULL ;
IDXGISwapChain * swapchain = NULL ;
D3D_FEATURE_LEVEL featlevel ;
D3DTexture2D * backbuf = NULL ;
HWND hWnd ;
2010-06-19 01:02:43 +00:00
bool bgra_textures_supported ;
2010-06-14 22:38:47 +00:00
# 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
} ;
2010-06-13 19:50:06 +00:00
unsigned int xres , yres ;
bool bFrameInProgress = false ;
HRESULT Create ( HWND wnd )
{
hWnd = wnd ;
HRESULT hr ;
RECT client ;
GetClientRect ( hWnd , & client ) ;
xres = client . right - client . left ;
yres = client . bottom - client . top ;
2010-06-27 14:04:49 +00:00
// try to load D3DX11 first to check whether we have proper runtime support
// try to use the dll the plugin was compiled against first - don't bother about debug runtimes
hD3DXDll = LoadLibraryA ( StringFromFormat ( " d3dx11_%d.dll " , D3DX11_SDK_VERSION ) . c_str ( ) ) ;
if ( ! hD3DXDll )
{
// if that fails, use the dll which should be available in every SDK which officially supports DX11.
hD3DXDll = LoadLibraryA ( " d3dx11_42.dll " ) ;
if ( ! hD3DXDll )
{
MessageBoxA ( NULL , " Failed to load d3dx11_42.dll, update your DX11 runtime, please " , " Critical error " , MB_OK | MB_ICONERROR ) ;
return E_FAIL ;
}
else
{
NOTICE_LOG ( VIDEO , " Successfully loaded d3dx11_42.dll. If you're having trouble, try updating your DX runtime first. " ) ;
}
}
2010-06-27 16:08:54 +00:00
PD3DX11CompileFromMemory = ( D3DX11COMPILEFROMMEMORYTYPE ) GetProcAddress ( hD3DXDll , " D3DX11CompileFromMemory " ) ;
if ( PD3DX11CompileFromMemory = = NULL ) MessageBoxA ( NULL , " GetProcAddress failed for D3DX11CompileFromMemory! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
2010-06-27 14:04:49 +00:00
PD3DX11FilterTexture = ( D3DX11FILTERTEXTURETYPE ) GetProcAddress ( hD3DXDll , " D3DX11FilterTexture " ) ;
2010-06-27 16:08:54 +00:00
if ( PD3DX11FilterTexture = = NULL ) MessageBoxA ( NULL , " GetProcAddress failed for D3DX11FilterTexture! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
2010-06-27 14:04:49 +00:00
PD3DX11SaveTextureToFileA = ( D3DX11SAVETEXTURETOFILEATYPE ) GetProcAddress ( hD3DXDll , " D3DX11SaveTextureToFileA " ) ;
2010-06-27 16:08:54 +00:00
if ( PD3DX11SaveTextureToFileA = = NULL ) MessageBoxA ( NULL , " GetProcAddress failed for D3DX11SaveTextureToFileA! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
2010-06-27 14:04:49 +00:00
PD3DX11SaveTextureToFileW = ( D3DX11SAVETEXTURETOFILEWTYPE ) GetProcAddress ( hD3DXDll , " D3DX11SaveTextureToFileW " ) ;
2010-06-27 16:08:54 +00:00
if ( PD3DX11SaveTextureToFileW = = NULL ) MessageBoxA ( NULL , " GetProcAddress failed for D3DX11SaveTextureToFileW! " , " Critical error " , MB_OK | MB_ICONERROR ) ;
2010-06-27 14:04:49 +00:00
// D3DX11 is fine, initialize D3D11
2010-06-14 19:20:41 +00:00
IDXGIFactory * factory ;
IDXGIAdapter * adapter ;
IDXGIOutput * output ;
hr = CreateDXGIFactory ( __uuidof ( IDXGIFactory ) , ( void * * ) & factory ) ;
if ( FAILED ( hr ) ) MessageBox ( wnd , _T ( " Failed to create IDXGIFactory object " ) , _T ( " Dolphin Direct3D 11 plugin " ) , MB_OK | MB_ICONERROR ) ;
hr = factory - > EnumAdapters ( g_ActiveConfig . iAdapter , & adapter ) ;
if ( FAILED ( hr ) )
{
// try using the first one
hr = factory - > EnumAdapters ( 0 , & adapter ) ;
2010-06-16 10:12:57 +00:00
if ( FAILED ( hr ) ) MessageBox ( wnd , _T ( " Failed to enumerate adapters " ) , _T ( " Dolphin Direct3D 11 plugin " ) , MB_OK | MB_ICONERROR ) ;
2010-06-14 19:20:41 +00:00
}
// TODO: Make this configurable
hr = adapter - > EnumOutputs ( 0 , & output ) ;
if ( FAILED ( hr ) )
{
// try using the first one
hr = adapter - > EnumOutputs ( 0 , & output ) ;
2010-06-16 10:12:57 +00:00
if ( FAILED ( hr ) ) MessageBox ( wnd , _T ( " Failed to enumerate outputs " ) , _T ( " Dolphin Direct3D 11 plugin " ) , MB_OK | MB_ICONERROR ) ;
2010-06-14 19:20:41 +00:00
}
// this will need to be changed once multisampling gets implemented
DXGI_SWAP_CHAIN_DESC swap_chain_desc ;
memset ( & swap_chain_desc , 0 , sizeof ( 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 = TRUE ;
DXGI_MODE_DESC mode_desc ;
memset ( & mode_desc , 0 , sizeof ( mode_desc ) ) ;
mode_desc . Width = xres ;
mode_desc . Height = yres ;
mode_desc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
mode_desc . Scaling = DXGI_MODE_SCALING_UNSPECIFIED ;
hr = output - > FindClosestMatchingMode ( & mode_desc , & swap_chain_desc . BufferDesc , NULL ) ;
if ( FAILED ( hr ) ) MessageBox ( wnd , _T ( " Failed to find a supported video mode " ) , _T ( " Dolphin Direct3D 11 plugin " ) , MB_OK | MB_ICONERROR ) ;
2010-06-14 21:31:23 +00:00
// forcing buffer resolution to xres and yres.. TODO: The new video mode might not actually be supported!
swap_chain_desc . BufferDesc . Width = xres ;
swap_chain_desc . BufferDesc . Height = yres ;
2010-06-13 19:50:06 +00:00
# if defined(_DEBUG) || defined(DEBUGFAST)
D3D11_CREATE_DEVICE_FLAG device_flags = ( D3D11_CREATE_DEVICE_FLAG ) ( D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_SINGLETHREADED ) ;
# else
D3D11_CREATE_DEVICE_FLAG device_flags = D3D11_CREATE_DEVICE_SINGLETHREADED ;
# endif
2010-06-14 22:38:47 +00:00
hr = D3D11CreateDeviceAndSwapChain ( adapter , D3D_DRIVER_TYPE_UNKNOWN , NULL , device_flags ,
supported_feature_levels , NUM_SUPPORTED_FEATURE_LEVELS ,
D3D11_SDK_VERSION , & swap_chain_desc , & swapchain , & device ,
& featlevel , & context ) ;
2010-06-13 19:50:06 +00:00
if ( FAILED ( hr ) | | ! device | | ! context | | ! swapchain )
{
2010-06-14 22:38:47 +00:00
MessageBox ( wnd , _T ( " Failed to initialize Direct3D. \n Make sure your video card supports at least D3D 10.0 " ) , _T ( " Dolphin Direct3D 11 plugin " ) , MB_OK | MB_ICONERROR ) ;
2010-06-13 19:50:06 +00:00
SAFE_RELEASE ( device ) ;
SAFE_RELEASE ( context ) ;
SAFE_RELEASE ( swapchain ) ;
return E_FAIL ;
}
SetDebugObjectName ( ( ID3D11DeviceChild * ) context , " device context " ) ;
2010-07-17 11:42:28 +00:00
SAFE_RELEASE ( factory ) ;
SAFE_RELEASE ( output ) ;
SAFE_RELEASE ( adapter ) ;
2010-06-13 19:50:06 +00:00
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 plugin " ) , MB_OK | MB_ICONERROR ) ;
2010-07-17 11:42:28 +00:00
SAFE_RELEASE ( device ) ;
SAFE_RELEASE ( context ) ;
SAFE_RELEASE ( swapchain ) ;
2010-06-13 19:50:06 +00:00
return E_FAIL ;
}
backbuf = new D3DTexture2D ( buf , D3D11_BIND_RENDER_TARGET ) ;
2010-07-17 11:42:28 +00:00
SAFE_RELEASE ( buf ) ;
2010-06-18 18:40:58 +00:00
CHECK ( backbuf ! = NULL , " Create back buffer texture " ) ;
2010-06-13 19:50:06 +00:00
SetDebugObjectName ( ( ID3D11DeviceChild * ) backbuf - > GetTex ( ) , " backbuffer texture " ) ;
SetDebugObjectName ( ( ID3D11DeviceChild * ) backbuf - > GetRTV ( ) , " backbuffer render target view " ) ;
context - > OMSetRenderTargets ( 1 , & backbuf - > GetRTV ( ) , NULL ) ;
2010-06-19 01:02:43 +00:00
// 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 ;
2010-06-13 19:50:06 +00:00
gfxstate = new EmuGfxState ;
2010-06-18 23:33:07 +00:00
stateman = new StateManager ;
2010-06-13 19:50:06 +00:00
return S_OK ;
}
void Close ( )
{
2010-06-27 14:04:49 +00:00
// unload D3DX11
FreeLibrary ( hD3DXDll ) ;
PD3DX11FilterTexture = NULL ;
PD3DX11SaveTextureToFileA = NULL ;
PD3DX11SaveTextureToFileW = NULL ;
2010-06-13 19:50:06 +00:00
// release all bound resources
context - > ClearState ( ) ;
SAFE_RELEASE ( backbuf ) ;
SAFE_RELEASE ( swapchain ) ;
2010-06-18 23:33:07 +00:00
SAFE_DELETE ( gfxstate ) ;
SAFE_DELETE ( stateman ) ;
2010-06-17 10:42:57 +00:00
context - > Flush ( ) ; // immediately destroy device objects
SAFE_RELEASE ( context ) ;
2010-06-13 19:50:06 +00:00
ULONG references = device - > Release ( ) ;
if ( references )
{
ERROR_LOG ( VIDEO , " Unreleased references: %i. " , references ) ;
}
else
{
NOTICE_LOG ( VIDEO , " Successfully released all device references! " ) ;
}
device = NULL ;
}
/* just returning the 4_0 ones here */
const char * VertexShaderVersionString ( ) { return " vs_4_0 " ; }
const char * PixelShaderVersionString ( ) { return " ps_4_0 " ; }
D3DTexture2D * & GetBackBuffer ( ) { return backbuf ; }
unsigned int GetBackBufferWidth ( ) { return xres ; }
unsigned int GetBackBufferHeight ( ) { return yres ; }
2010-06-19 01:02:43 +00:00
bool BGRATexturesSupported ( ) { return bgra_textures_supported ; }
2010-07-11 16:26:46 +00:00
// 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 16384 ;
case D3D_FEATURE_LEVEL_10_1 :
case D3D_FEATURE_LEVEL_10_0 :
return 8192 ;
case D3D_FEATURE_LEVEL_9_3 :
return 4096 ;
case D3D_FEATURE_LEVEL_9_2 :
case D3D_FEATURE_LEVEL_9_1 :
return 2048 ;
2010-07-17 11:42:28 +00:00
default :
return 0 ;
2010-07-11 16:26:46 +00:00
}
}
2010-06-13 19:50:06 +00:00
void Reset ( )
{
2010-06-17 10:42:57 +00:00
// 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 ) ;
// 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 plugin " ) , MB_OK | MB_ICONERROR ) ;
2010-07-17 11:42:28 +00:00
SAFE_RELEASE ( device ) ;
SAFE_RELEASE ( context ) ;
SAFE_RELEASE ( swapchain ) ;
2010-06-17 10:42:57 +00:00
return ;
}
backbuf = new D3DTexture2D ( buf , D3D11_BIND_RENDER_TARGET ) ;
2010-07-17 11:42:28 +00:00
SAFE_RELEASE ( buf ) ;
2010-06-18 18:40:58 +00:00
CHECK ( backbuf ! = NULL , " Create back buffer texture " ) ;
2010-06-17 10:42:57 +00:00
SetDebugObjectName ( ( ID3D11DeviceChild * ) backbuf - > GetTex ( ) , " backbuffer texture " ) ;
SetDebugObjectName ( ( ID3D11DeviceChild * ) backbuf - > GetRTV ( ) , " backbuffer render target view " ) ;
2010-06-13 19:50:06 +00:00
}
bool BeginFrame ( )
{
if ( bFrameInProgress )
{
PanicAlert ( " BeginFrame called although a frame is already in progress " ) ;
return false ;
}
bFrameInProgress = true ;
return ( device ! = NULL ) ;
}
void EndFrame ( )
{
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 . bVSync , 0 ) ;
}
} // namespace