2015-05-24 06:55:12 +02:00
// Copyright 2010 Dolphin Emulator Project
2015-05-18 01:08:10 +02:00
// Licensed under GPLv2+
2013-04-17 23:29:41 -04:00
// Refer to the license.txt file included.
2010-06-13 19:50:06 +00:00
2013-10-26 11:55:41 +02:00
#include <cinttypes>
#include <cmath>
2015-12-22 18:47:20 -05:00
#include <memory>
2014-05-25 20:52:58 -04:00
#include <string>
2012-12-23 20:25:11 +13:00
#include <strsafe.h>
2014-06-05 13:58:36 +02:00
#include <unordered_map>
2014-02-17 05:18:15 -05:00
2016-01-17 16:54:31 -05:00
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
2015-05-07 00:37:58 +02:00
#include "Common/MathUtil.h"
2014-02-17 05:18:15 -05:00
#include "Core/ConfigManager.h"
2014-02-19 12:14:09 +01:00
#include "Core/Core.h"
2014-02-17 05:18:15 -05:00
#include "Core/Host.h"
2014-12-04 23:01:20 -03:00
#include "VideoBackends/D3D/BoundingBox.h"
2014-02-17 05:18:15 -05:00
#include "VideoBackends/D3D/D3DBase.h"
2014-06-23 08:11:07 +02:00
#include "VideoBackends/D3D/D3DState.h"
2014-02-17 05:18:15 -05:00
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/FramebufferManager.h"
2014-11-15 01:53:08 +01:00
#include "VideoBackends/D3D/GeometryShaderCache.h"
2014-02-17 05:18:15 -05:00
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/Render.h"
#include "VideoBackends/D3D/Television.h"
#include "VideoBackends/D3D/TextureCache.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/AVIDump.h"
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/PixelEngine.h"
2015-01-03 06:06:56 +13:00
#include "VideoCommon/PixelShaderManager.h"
2016-03-24 02:42:08 +00:00
#include "VideoCommon/SamplerCommon.h"
2014-02-17 05:18:15 -05:00
#include "VideoCommon/VideoConfig.h"
2010-06-13 19:50:06 +00:00
2011-01-29 20:16:51 +00:00
namespace DX11
{
2015-12-12 13:00:08 +01:00
static u32 s_last_multisamples = 1 ;
2015-01-04 16:33:58 +01:00
static bool s_last_stereo_mode = false ;
static bool s_last_xfb_mode = false ;
2010-11-23 19:58:02 +00:00
2011-06-11 19:37:21 +00:00
static Television s_television ;
2014-03-09 21:14:26 +01:00
ID3D11Buffer * access_efb_cbuf = nullptr ;
ID3D11BlendState * clearblendstates [ 4 ] = { nullptr };
ID3D11DepthStencilState * cleardepthstates [ 3 ] = { nullptr };
ID3D11BlendState * resetblendstate = nullptr ;
ID3D11DepthStencilState * resetdepthstate = nullptr ;
ID3D11RasterizerState * resetraststate = nullptr ;
2010-06-13 19:50:06 +00:00
2014-03-09 21:14:26 +01:00
static ID3D11Texture2D * s_screenshot_texture = nullptr ;
2014-11-14 00:24:53 +01:00
static D3DTexture2D * s_3d_vision_texture = nullptr ;
2014-11-29 21:37:34 +01:00
// Nvidia stereo blitting struct defined in "nvstereo.h" from the Nvidia SDK
2014-11-14 00:24:53 +01:00
typedef struct _Nv_Stereo_Image_Header
{
unsigned int dwSignature ;
unsigned int dwWidth ;
unsigned int dwHeight ;
unsigned int dwBPP ;
unsigned int dwFlags ;
} NVSTEREOIMAGEHEADER , * LPNVSTEREOIMAGEHEADER ;
#define NVSTEREO_IMAGE_SIGNATURE 0x4433564e
2011-09-08 15:39:03 +02:00
2011-01-24 08:44:32 +00:00
// GX pipeline state
struct
{
2014-06-05 13:58:36 +02:00
SamplerState sampler [ 8 ];
BlendState blend ;
ZMode zmode ;
RasterizerState raster ;
2011-01-24 08:44:32 +00:00
} gx_state ;
2014-06-09 00:36:26 +02:00
StateCache gx_state_cache ;
2012-08-07 14:55:10 +02:00
2015-12-08 23:45:07 +10:00
static void SetupDeviceObjects ()
2010-06-13 19:50:06 +00:00
{
2011-06-11 19:37:21 +00:00
s_television . Init ();
2015-12-22 18:47:20 -05:00
g_framebuffer_manager = std :: make_unique < FramebufferManager > ();
2010-06-13 19:50:06 +00:00
2010-07-18 10:11:34 +00:00
HRESULT hr ;
2010-06-13 19:50:06 +00:00
float colmat [ 20 ] = { 0.0f };
colmat [ 0 ] = colmat [ 5 ] = colmat [ 10 ] = 1.0f ;
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC ( 20 * sizeof ( float ), D3D11_BIND_CONSTANT_BUFFER , D3D11_USAGE_DEFAULT );
D3D11_SUBRESOURCE_DATA data ;
data . pSysMem = colmat ;
2011-06-11 19:37:21 +00:00
hr = D3D :: device -> CreateBuffer ( & cbdesc , & data , & access_efb_cbuf );
CHECK ( hr == S_OK , "Create constant buffer for Renderer::AccessEFB" );
D3D :: SetDebugObjectName (( ID3D11DeviceChild * ) access_efb_cbuf , "constant buffer for Renderer::AccessEFB" );
2010-06-13 19:50:06 +00:00
D3D11_DEPTH_STENCIL_DESC ddesc ;
2014-02-16 15:30:18 -05:00
ddesc . DepthEnable = FALSE ;
2010-06-15 21:19:09 +00:00
ddesc . DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO ;
2014-02-16 15:30:18 -05:00
ddesc . DepthFunc = D3D11_COMPARISON_ALWAYS ;
ddesc . StencilEnable = FALSE ;
2010-06-13 19:50:06 +00:00
ddesc . StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK ;
ddesc . StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK ;
2011-06-11 19:37:21 +00:00
hr = D3D :: device -> CreateDepthStencilState ( & ddesc , & cleardepthstates [ 0 ]);
2010-06-18 18:40:58 +00:00
CHECK ( hr == S_OK , "Create depth state for Renderer::ClearScreen" );
2010-06-15 21:19:09 +00:00
ddesc . DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL ;
2014-02-16 15:30:18 -05:00
ddesc . DepthEnable = TRUE ;
2011-06-11 19:37:21 +00:00
hr = D3D :: device -> CreateDepthStencilState ( & ddesc , & cleardepthstates [ 1 ]);
2010-06-18 18:40:58 +00:00
CHECK ( hr == S_OK , "Create depth state for Renderer::ClearScreen" );
2010-11-01 19:13:50 +00:00
ddesc . DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO ;
2011-06-11 19:37:21 +00:00
hr = D3D :: device -> CreateDepthStencilState ( & ddesc , & cleardepthstates [ 2 ]);
2010-11-01 19:13:50 +00:00
CHECK ( hr == S_OK , "Create depth state for Renderer::ClearScreen" );
2011-06-11 19:37:21 +00:00
D3D :: SetDebugObjectName (( ID3D11DeviceChild * ) cleardepthstates [ 0 ], "depth state for Renderer::ClearScreen (depth buffer disabled)" );
D3D :: SetDebugObjectName (( ID3D11DeviceChild * ) cleardepthstates [ 1 ], "depth state for Renderer::ClearScreen (depth buffer enabled, writing enabled)" );
D3D :: SetDebugObjectName (( ID3D11DeviceChild * ) cleardepthstates [ 2 ], "depth state for Renderer::ClearScreen (depth buffer enabled, writing disabled)" );
2010-06-13 19:50:06 +00:00
D3D11_BLEND_DESC blenddesc ;
blenddesc . AlphaToCoverageEnable = FALSE ;
blenddesc . IndependentBlendEnable = FALSE ;
blenddesc . RenderTarget [ 0 ]. BlendEnable = FALSE ;
blenddesc . RenderTarget [ 0 ]. RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL ;
blenddesc . RenderTarget [ 0 ]. SrcBlend = D3D11_BLEND_ONE ;
blenddesc . RenderTarget [ 0 ]. DestBlend = D3D11_BLEND_ZERO ;
blenddesc . RenderTarget [ 0 ]. BlendOp = D3D11_BLEND_OP_ADD ;
blenddesc . RenderTarget [ 0 ]. SrcBlendAlpha = D3D11_BLEND_ONE ;
blenddesc . RenderTarget [ 0 ]. DestBlendAlpha = D3D11_BLEND_ZERO ;
blenddesc . RenderTarget [ 0 ]. BlendOpAlpha = D3D11_BLEND_OP_ADD ;
2011-06-11 19:37:21 +00:00
hr = D3D :: device -> CreateBlendState ( & blenddesc , & resetblendstate );
CHECK ( hr == S_OK , "Create blend state for Renderer::ResetAPIState" );
D3D :: SetDebugObjectName (( ID3D11DeviceChild * ) resetblendstate , "blend state for Renderer::ResetAPIState" );
2010-06-13 19:50:06 +00:00
2010-10-24 16:53:33 +00:00
clearblendstates [ 0 ] = resetblendstate ;
2011-06-11 19:37:21 +00:00
resetblendstate -> AddRef ();
2010-10-24 16:53:33 +00:00
2011-06-11 19:37:21 +00:00
blenddesc . RenderTarget [ 0 ]. RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE ;
hr = D3D :: device -> CreateBlendState ( & blenddesc , & clearblendstates [ 1 ]);
CHECK ( hr == S_OK , "Create blend state for Renderer::ClearScreen" );
2010-10-24 16:53:33 +00:00
blenddesc . RenderTarget [ 0 ]. RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA ;
2011-06-11 19:37:21 +00:00
hr = D3D :: device -> CreateBlendState ( & blenddesc , & clearblendstates [ 2 ]);
CHECK ( hr == S_OK , "Create blend state for Renderer::ClearScreen" );
2010-10-24 16:53:33 +00:00
blenddesc . RenderTarget [ 0 ]. RenderTargetWriteMask = 0 ;
2011-06-11 19:37:21 +00:00
hr = D3D :: device -> CreateBlendState ( & blenddesc , & clearblendstates [ 3 ]);
CHECK ( hr == S_OK , "Create blend state for Renderer::ClearScreen" );
2010-10-24 16:53:33 +00:00
2014-02-16 15:30:18 -05:00
ddesc . DepthEnable = FALSE ;
ddesc . DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO ;
ddesc . DepthFunc = D3D11_COMPARISON_LESS ;
ddesc . StencilEnable = FALSE ;
ddesc . StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK ;
ddesc . StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK ;
2011-06-11 19:37:21 +00:00
hr = D3D :: device -> CreateDepthStencilState ( & ddesc , & resetdepthstate );
2010-06-18 18:40:58 +00:00
CHECK ( hr == S_OK , "Create depth state for Renderer::ResetAPIState" );
2011-06-11 19:37:21 +00:00
D3D :: SetDebugObjectName (( ID3D11DeviceChild * ) resetdepthstate , "depth stencil state for Renderer::ResetAPIState" );
2010-06-13 19:50:06 +00:00
D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC ( D3D11_FILL_SOLID , D3D11_CULL_NONE , false , 0 , 0.f , 0.f , false , false , false , false );
2011-06-11 19:37:21 +00:00
hr = D3D :: device -> CreateRasterizerState ( & rastdesc , & resetraststate );
2010-11-01 19:13:50 +00:00
CHECK ( hr == S_OK , "Create rasterizer state for Renderer::ResetAPIState" );
2011-06-11 19:37:21 +00:00
D3D :: SetDebugObjectName (( ID3D11DeviceChild * ) resetraststate , "rasterizer state for Renderer::ResetAPIState" );
2011-09-08 15:39:03 +02:00
2014-03-09 21:14:26 +01:00
s_screenshot_texture = nullptr ;
2010-06-13 19:50:06 +00:00
}
2011-09-08 15:39:03 +02:00
// Kill off all device objects
2015-12-08 23:45:07 +10:00
static void TeardownDeviceObjects ()
2010-06-13 19:50:06 +00:00
{
2015-12-22 18:47:20 -05:00
g_framebuffer_manager . reset ();
2010-11-14 23:31:53 +00:00
2011-06-11 19:37:21 +00:00
SAFE_RELEASE ( access_efb_cbuf );
SAFE_RELEASE ( clearblendstates [ 0 ]);
SAFE_RELEASE ( clearblendstates [ 1 ]);
SAFE_RELEASE ( clearblendstates [ 2 ]);
SAFE_RELEASE ( clearblendstates [ 3 ]);
2010-06-13 19:50:06 +00:00
SAFE_RELEASE ( cleardepthstates [ 0 ]);
SAFE_RELEASE ( cleardepthstates [ 1 ]);
2010-11-01 19:13:50 +00:00
SAFE_RELEASE ( cleardepthstates [ 2 ]);
2011-06-11 19:37:21 +00:00
SAFE_RELEASE ( resetblendstate );
2010-06-13 19:50:06 +00:00
SAFE_RELEASE ( resetdepthstate );
SAFE_RELEASE ( resetraststate );
2011-09-08 15:39:03 +02:00
SAFE_RELEASE ( s_screenshot_texture );
2014-12-03 22:39:00 +01:00
SAFE_RELEASE ( s_3d_vision_texture );
2011-06-11 19:37:21 +00:00
s_television . Shutdown ();
2014-06-05 13:58:36 +02:00
gx_state_cache . Clear ();
2010-06-13 19:50:06 +00:00
}
2015-12-08 23:45:07 +10:00
static void CreateScreenshotTexture ()
2012-08-07 14:55:10 +02:00
{
2015-12-08 23:45:07 +10:00
// We can't render anything outside of the backbuffer anyway, so use the backbuffer size as the screenshot buffer size.
// This texture is released to be recreated when the window is resized in Renderer::SwapImpl.
D3D11_TEXTURE2D_DESC scrtex_desc = CD3D11_TEXTURE2D_DESC ( DXGI_FORMAT_R8G8B8A8_UNORM , D3D :: GetBackBufferWidth (), D3D :: GetBackBufferHeight (), 1 , 1 , 0 , D3D11_USAGE_STAGING , D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE );
2014-03-09 21:14:26 +01:00
HRESULT hr = D3D :: device -> CreateTexture2D ( & scrtex_desc , nullptr , & s_screenshot_texture );
2012-08-07 14:55:10 +02:00
CHECK ( hr == S_OK , "Create screenshot staging texture" );
D3D :: SetDebugObjectName (( ID3D11DeviceChild * ) s_screenshot_texture , "staging screenshot texture" );
}
2015-12-08 23:45:07 +10:00
static D3D11_BOX GetScreenshotSourceBox ( const TargetRectangle & targetRc )
{
// Since the screenshot buffer is copied back to the CPU via Map(), we can't access pixels that
// fall outside the backbuffer bounds. Therefore, when crop is enabled and the target rect is
// off-screen to the top/left, we clamp the origin at zero, as well as the bottom/right
// coordinates at the backbuffer dimensions. This will result in a rectangle that can be
// smaller than the backbuffer, but never larger.
return CD3D11_BOX (
std :: max ( targetRc . left , 0 ),
std :: max ( targetRc . top , 0 ),
0 ,
std :: min ( D3D :: GetBackBufferWidth (), ( unsigned int ) targetRc . right ),
std :: min ( D3D :: GetBackBufferHeight (), ( unsigned int ) targetRc . bottom ),
1 );
}
static void Create3DVisionTexture ( int width , int height )
2014-11-14 00:24:53 +01:00
{
// Create a staging texture for 3D vision with signature information in the last row.
// Nvidia 3D Vision supports full SBS, so there is no loss in resolution during this process.
D3D11_SUBRESOURCE_DATA sysData ;
sysData . SysMemPitch = 4 * width * 2 ;
sysData . pSysMem = new u8 [( height + 1 ) * sysData . SysMemPitch ];
LPNVSTEREOIMAGEHEADER header = ( LPNVSTEREOIMAGEHEADER )(( u8 * ) sysData . pSysMem + height * sysData . SysMemPitch );
header -> dwSignature = NVSTEREO_IMAGE_SIGNATURE ;
header -> dwWidth = width * 2 ;
header -> dwHeight = height + 1 ;
header -> dwBPP = 32 ;
header -> dwFlags = 0 ;
s_3d_vision_texture = D3DTexture2D :: Create ( width * 2 , height + 1 , D3D11_BIND_RENDER_TARGET , D3D11_USAGE_DEFAULT , DXGI_FORMAT_R8G8B8A8_UNORM , 1 , 1 , & sysData );
delete [] sysData . pSysMem ;
}
2014-06-15 00:23:43 +02:00
Renderer :: Renderer ( void *& window_handle )
2010-06-13 19:50:06 +00:00
{
2014-06-15 00:23:43 +02:00
D3D :: Create (( HWND ) window_handle );
2010-06-13 19:50:06 +00:00
s_backbuffer_width = D3D :: GetBackBufferWidth ();
s_backbuffer_height = D3D :: GetBackBufferHeight ();
2012-09-28 23:48:18 +02:00
FramebufferManagerBase :: SetLastXfbWidth ( MAX_XFB_WIDTH );
FramebufferManagerBase :: SetLastXfbHeight ( MAX_XFB_HEIGHT );
2010-06-13 19:50:06 +00:00
2012-09-29 00:04:55 +02:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height );
2010-06-13 19:50:06 +00:00
2015-12-12 13:00:08 +01:00
s_last_multisamples = g_ActiveConfig . iMultisamples ;
2014-12-28 18:35:23 +01:00
s_last_efb_scale = g_ActiveConfig . iEFBScale ;
s_last_stereo_mode = g_ActiveConfig . iStereoMode > 0 ;
2014-12-28 18:26:25 +01:00
s_last_xfb_mode = g_ActiveConfig . bUseRealXFB ;
2012-09-29 00:19:28 +02:00
CalculateTargetSize ( s_backbuffer_width , s_backbuffer_height );
2015-01-03 06:06:56 +13:00
PixelShaderManager :: SetEfbScaleChanged ();
2010-06-13 19:50:06 +00:00
SetupDeviceObjects ();
2011-01-24 08:44:32 +00:00
// Setup GX pipeline state
2014-06-05 13:58:36 +02:00
gx_state . blend . blend_enable = false ;
gx_state . blend . write_mask = D3D11_COLOR_WRITE_ENABLE_ALL ;
gx_state . blend . src_blend = D3D11_BLEND_ONE ;
gx_state . blend . dst_blend = D3D11_BLEND_ZERO ;
gx_state . blend . blend_op = D3D11_BLEND_OP_ADD ;
gx_state . blend . use_dst_alpha = false ;
2011-01-24 09:27:16 +00:00
2011-01-24 08:44:32 +00:00
for ( unsigned int k = 0 ; k < 8 ; k ++ )
{
2014-06-05 13:58:36 +02:00
gx_state . sampler [ k ]. packed = 0 ;
2011-01-24 08:44:32 +00:00
}
2010-06-13 19:50:06 +00:00
2014-10-15 20:17:34 +02:00
gx_state . zmode . testenable = false ;
gx_state . zmode . updateenable = false ;
gx_state . zmode . func = ZMode :: NEVER ;
gx_state . raster . cull_mode = D3D11_CULL_NONE ;
2011-01-24 08:44:32 +00:00
// Clear EFB textures
2010-12-21 22:18:40 +00:00
float ClearColor [ 4 ] = { 0.f , 0.f , 0.f , 1.f };
2011-06-11 19:37:21 +00:00
D3D :: context -> ClearRenderTargetView ( FramebufferManager :: GetEFBColorTexture () -> GetRTV (), ClearColor );
2015-05-25 23:29:47 +02:00
D3D :: context -> ClearDepthStencilView ( FramebufferManager :: GetEFBDepthTexture () -> GetDSV (), D3D11_CLEAR_DEPTH , 0.f , 0 );
2010-06-13 19:50:06 +00:00
2011-06-11 19:37:21 +00:00
D3D11_VIEWPORT vp = CD3D11_VIEWPORT ( 0.f , 0.f , ( float ) s_target_width , ( float ) s_target_height );
D3D :: context -> RSSetViewports ( 1 , & vp );
D3D :: context -> OMSetRenderTargets ( 1 , & FramebufferManager :: GetEFBColorTexture () -> GetRTV (), FramebufferManager :: GetEFBDepthTexture () -> GetDSV ());
2010-06-13 19:50:06 +00:00
D3D :: BeginFrame ();
}
2010-11-18 02:21:26 +00:00
Renderer ::~ Renderer ()
2010-06-13 19:50:06 +00:00
{
TeardownDeviceObjects ();
D3D :: EndFrame ();
D3D :: Present ();
D3D :: Close ();
}
2014-03-12 15:33:41 -04:00
void Renderer :: RenderText ( const std :: string & text , int left , int top , u32 color )
2010-06-13 19:50:06 +00:00
{
2014-12-20 13:31:41 +01:00
D3D :: font . DrawTextScaled (( float )( left + 1 ), ( float )( top + 1 ), 20.f , 0.0f , color & 0xFF000000 , text );
2010-11-07 10:11:58 +00:00
D3D :: font . DrawTextScaled (( float ) left , ( float ) top , 20.f , 0.0f , color , text );
2010-06-13 19:50:06 +00:00
}
TargetRectangle Renderer :: ConvertEFBRectangle ( const EFBRectangle & rc )
{
TargetRectangle result ;
2011-05-12 02:14:45 +00:00
result . left = EFBToScaledX ( rc . left );
result . top = EFBToScaledY ( rc . top );
result . right = EFBToScaledX ( rc . right );
result . bottom = EFBToScaledY ( rc . bottom );
2010-06-13 19:50:06 +00:00
return result ;
}
2010-09-28 02:15:02 +00:00
// With D3D, we have to resize the backbuffer if the window changed
// size.
2010-11-18 02:21:26 +00:00
bool Renderer :: CheckForResize ()
2010-06-13 19:50:06 +00:00
{
RECT rcWindow ;
2014-06-15 00:23:43 +02:00
GetClientRect ( D3D :: hWnd , & rcWindow );
2010-06-13 19:50:06 +00:00
int client_width = rcWindow . right - rcWindow . left ;
int client_height = rcWindow . bottom - rcWindow . top ;
2010-09-28 02:15:02 +00:00
// Sanity check
2010-11-18 02:21:26 +00:00
if (( client_width != Renderer :: GetBackbufferWidth () ||
2013-10-29 01:23:17 -04:00
client_height != Renderer :: GetBackbufferHeight ()) &&
2010-06-13 19:50:06 +00:00
client_width >= 4 && client_height >= 4 )
{
2010-11-18 02:21:26 +00:00
return true ;
2010-06-13 19:50:06 +00:00
}
2010-11-18 02:21:26 +00:00
return false ;
2010-06-13 19:50:06 +00:00
}
2014-02-04 21:17:38 +01:00
void Renderer :: SetScissorRect ( const EFBRectangle & rc )
2010-06-13 19:50:06 +00:00
{
2014-02-04 21:17:38 +01:00
TargetRectangle trc = ConvertEFBRectangle ( rc );
D3D :: context -> RSSetScissorRects ( 1 , trc . AsRECT ());
2010-06-13 19:50:06 +00:00
}
2010-06-16 10:12:57 +00:00
void Renderer :: SetColorMask ()
2010-06-13 19:50:06 +00:00
{
2010-12-20 16:57:29 +00:00
// Only enable alpha channel if it's supported by the current EFB format
2010-06-13 19:50:06 +00:00
UINT8 color_mask = 0 ;
2013-01-08 17:23:01 +01:00
if ( bpmem . alpha_test . TestResult () != AlphaTest :: FAIL )
{
2014-03-23 21:44:23 +01:00
if ( bpmem . blendmode . alphaupdate && ( bpmem . zcontrol . pixel_format == PEControl :: RGBA6_Z24 ))
2013-01-08 17:23:01 +01:00
color_mask = D3D11_COLOR_WRITE_ENABLE_ALPHA ;
if ( bpmem . blendmode . colorupdate )
color_mask |= D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE ;
}
2014-06-05 13:58:36 +02:00
gx_state . blend . write_mask = color_mask ;
2010-06-13 19:50:06 +00:00
}
2010-10-24 19:52:52 +00:00
// This function allows the CPU to directly access the EFB.
// There are EFB peeks (which will read the color or depth of a pixel)
// and EFB pokes (which will change the color or depth of a pixel).
//
// The behavior of EFB peeks can only be modified by:
2014-02-16 15:30:18 -05:00
// - GX_PokeAlphaRead
2010-10-24 19:52:52 +00:00
// The behavior of EFB pokes can be modified by:
2014-02-16 15:30:18 -05:00
// - GX_PokeAlphaMode (TODO)
// - GX_PokeAlphaUpdate (TODO)
// - GX_PokeBlendMode (TODO)
// - GX_PokeColorUpdate (TODO)
// - GX_PokeDither (TODO)
// - GX_PokeDstAlpha (TODO)
// - GX_PokeZMode (TODO)
2010-10-22 19:40:05 +00:00
u32 Renderer :: AccessEFB ( EFBAccessType type , u32 x , u32 y , u32 poke_data )
2010-06-13 19:50:06 +00:00
{
2010-11-23 19:58:02 +00:00
// TODO: This function currently is broken if anti-aliasing is enabled
2010-10-22 19:40:05 +00:00
D3D11_MAPPED_SUBRESOURCE map ;
2010-06-21 17:54:13 +00:00
ID3D11Texture2D * read_tex ;
2010-06-13 19:50:06 +00:00
2010-10-02 11:50:50 +00:00
// Convert EFB dimensions to the ones of our render target
2010-06-13 19:50:06 +00:00
EFBRectangle efbPixelRc ;
efbPixelRc . left = x ;
efbPixelRc . top = y ;
efbPixelRc . right = x + 1 ;
efbPixelRc . bottom = y + 1 ;
TargetRectangle targetPixelRc = Renderer :: ConvertEFBRectangle ( efbPixelRc );
2010-10-22 19:40:05 +00:00
// Take the mean of the resulting dimensions; TODO: Don't use the center pixel, compute the average color instead
2010-10-02 11:50:50 +00:00
D3D11_RECT RectToLock ;
2014-03-11 00:30:55 +13:00
if ( type == PEEK_COLOR || type == PEEK_Z )
2010-10-22 19:40:05 +00:00
{
RectToLock . left = ( targetPixelRc . left + targetPixelRc . right ) / 2 ;
RectToLock . top = ( targetPixelRc . top + targetPixelRc . bottom ) / 2 ;
RectToLock . right = RectToLock . left + 1 ;
RectToLock . bottom = RectToLock . top + 1 ;
}
else
{
RectToLock . left = targetPixelRc . left ;
RectToLock . right = targetPixelRc . right ;
RectToLock . top = targetPixelRc . top ;
RectToLock . bottom = targetPixelRc . bottom ;
}
2010-06-13 19:50:06 +00:00
if ( type == PEEK_Z )
{
2010-09-28 02:15:02 +00:00
ResetAPIState (); // Reset any game specific settings
2010-06-13 19:50:06 +00:00
2010-10-02 11:50:50 +00:00
// depth buffers can only be completely CopySubresourceRegion'ed, so we're using drawShadedTexQuad instead
D3D11_VIEWPORT vp = CD3D11_VIEWPORT ( 0.f , 0.f , 1.f , 1.f );
2011-06-11 19:37:21 +00:00
D3D :: context -> RSSetViewports ( 1 , & vp );
2014-12-06 14:54:06 +01:00
D3D :: stateman -> SetPixelConstants ( 0 , access_efb_cbuf );
2014-03-09 21:14:26 +01:00
D3D :: context -> OMSetRenderTargets ( 1 , & FramebufferManager :: GetEFBDepthReadTexture () -> GetRTV (), nullptr );
2010-07-17 15:18:52 +00:00
D3D :: SetPointCopySampler ();
2010-11-27 11:11:05 +00:00
D3D :: drawShadedTexQuad ( FramebufferManager :: GetEFBDepthTexture () -> GetSRV (),
2010-06-13 19:50:06 +00:00
& RectToLock ,
2011-05-12 02:14:45 +00:00
Renderer :: GetTargetWidth (),
Renderer :: GetTargetHeight (),
2014-03-30 19:45:02 -07:00
PixelShaderCache :: GetColorCopyProgram ( true ),
2010-06-13 19:50:06 +00:00
VertexShaderCache :: GetSimpleVertexShader (),
VertexShaderCache :: GetSimpleInputLayout ());
2011-06-11 19:37:21 +00:00
D3D :: context -> OMSetRenderTargets ( 1 , & FramebufferManager :: GetEFBColorTexture () -> GetRTV (), FramebufferManager :: GetEFBDepthTexture () -> GetDSV ());
2010-06-13 19:50:06 +00:00
2010-06-21 17:54:13 +00:00
// copy to system memory
2010-10-02 11:50:50 +00:00
D3D11_BOX box = CD3D11_BOX ( 0 , 0 , 0 , 1 , 1 , 1 );
2010-11-14 23:31:53 +00:00
read_tex = FramebufferManager :: GetEFBDepthStagingBuffer ();
2011-06-11 19:37:21 +00:00
D3D :: context -> CopySubresourceRegion ( read_tex , 0 , 0 , 0 , 0 , FramebufferManager :: GetEFBDepthReadTexture () -> GetTex (), 0 , & box );
2010-10-02 11:50:50 +00:00
RestoreAPIState (); // restore game state
2010-10-22 19:40:05 +00:00
// read the data from system memory
2011-06-11 19:37:21 +00:00
D3D :: context -> Map ( read_tex , 0 , D3D11_MAP_READ , 0 , & map );
2010-10-22 19:40:05 +00:00
2015-05-24 14:44:25 +02:00
// depth buffer is inverted in the d3d backend
float val = 1.0f - * ( float * ) map . pData ;
2010-12-27 03:18:01 +00:00
u32 ret = 0 ;
2014-03-23 21:44:23 +01:00
if ( bpmem . zcontrol . pixel_format == PEControl :: RGB565_Z16 )
2010-12-27 03:18:01 +00:00
{
2010-12-27 18:09:03 +00:00
// if Z is in 16 bit format you must return a 16 bit integer
2015-05-07 00:37:58 +02:00
ret = MathUtil :: Clamp < u32 > (( u32 )( val * 65536.0f ), 0 , 0xFFFF );
2010-12-27 03:18:01 +00:00
}
else
{
2015-05-07 00:37:58 +02:00
ret = MathUtil :: Clamp < u32 > (( u32 )( val * 16777216.0f ), 0 , 0xFFFFFF );
2010-12-27 03:18:01 +00:00
}
2011-06-11 19:37:21 +00:00
D3D :: context -> Unmap ( read_tex , 0 );
2010-10-22 19:40:05 +00:00
return ret ;
2010-06-13 19:50:06 +00:00
}
2010-10-22 19:40:05 +00:00
else if ( type == PEEK_COLOR )
2010-06-13 19:50:06 +00:00
{
2010-06-21 17:54:13 +00:00
// we can directly copy to system memory here
2010-12-05 22:28:46 +00:00
read_tex = FramebufferManager :: GetEFBColorStagingBuffer ();
2010-06-13 19:50:06 +00:00
D3D11_BOX box = CD3D11_BOX ( RectToLock . left , RectToLock . top , 0 , RectToLock . right , RectToLock . bottom , 1 );
2011-06-11 19:37:21 +00:00
D3D :: context -> CopySubresourceRegion ( read_tex , 0 , 0 , 0 , 0 , FramebufferManager :: GetEFBColorTexture () -> GetTex (), 0 , & box );
2010-10-22 19:40:05 +00:00
// read the data from system memory
2011-06-11 19:37:21 +00:00
D3D :: context -> Map ( read_tex , 0 , D3D11_MAP_READ , 0 , & map );
2010-12-27 03:18:01 +00:00
u32 ret = 0 ;
2014-03-11 00:30:55 +13:00
if ( map . pData )
2010-12-27 03:18:01 +00:00
ret = * ( u32 * ) map . pData ;
2011-06-11 19:37:21 +00:00
D3D :: context -> Unmap ( read_tex , 0 );
2010-10-24 19:52:52 +00:00
// check what to do with the alpha channel (GX_PokeAlphaRead)
2014-02-15 03:23:35 +01:00
PixelEngine :: UPEAlphaReadReg alpha_read_mode = PixelEngine :: GetAlphaReadMode ();
2010-12-27 03:18:01 +00:00
2014-03-23 21:44:23 +01:00
if ( bpmem . zcontrol . pixel_format == PEControl :: RGBA6_Z24 )
2010-12-27 03:18:01 +00:00
{
ret = RGBA8ToRGBA6ToRGBA8 ( ret );
}
2014-03-23 21:44:23 +01:00
else if ( bpmem . zcontrol . pixel_format == PEControl :: RGB565_Z16 )
2010-12-27 03:18:01 +00:00
{
2010-12-27 18:09:03 +00:00
ret = RGBA8ToRGB565ToRGBA8 ( ret );
2013-10-29 01:23:17 -04:00
}
2014-03-23 21:44:23 +01:00
if ( bpmem . zcontrol . pixel_format != PEControl :: RGBA6_Z24 )
2010-12-27 03:18:01 +00:00
{
ret |= 0xFF000000 ;
}
2014-03-11 00:30:55 +13:00
if ( alpha_read_mode . ReadMode == 2 ) return ret ; // GX_READ_NONE
else if ( alpha_read_mode . ReadMode == 1 ) return ( ret | 0xFF000000 ); // GX_READ_FF
2010-10-24 19:52:52 +00:00
else /*if(alpha_read_mode.ReadMode == 0)*/ return ( ret & 0x00FFFFFF ); // GX_READ_00
2010-06-13 19:50:06 +00:00
}
2010-10-22 19:40:05 +00:00
2015-12-19 15:45:21 +10:00
return 0 ;
}
2010-09-28 02:15:02 +00:00
2015-12-20 00:34:56 +10:00
void Renderer :: PokeEFB ( EFBAccessType type , const EfbPokeData * points , size_t num_points )
2015-12-19 15:45:21 +10:00
{
ResetAPIState ();
if ( type == POKE_COLOR )
2010-09-28 02:15:02 +00:00
{
2015-06-07 13:32:00 +02:00
D3D11_VIEWPORT vp = CD3D11_VIEWPORT ( 0.0f , 0.0f , ( float ) GetTargetWidth (), ( float ) GetTargetHeight ());
D3D :: context -> RSSetViewports ( 1 , & vp );
2014-03-09 21:14:26 +01:00
D3D :: context -> OMSetRenderTargets ( 1 , & FramebufferManager :: GetEFBColorTexture () -> GetRTV (), nullptr );
2010-06-13 19:50:06 +00:00
}
2015-06-07 13:32:43 +02:00
else // if (type == POKE_Z)
{
D3D :: stateman -> PushBlendState ( clearblendstates [ 3 ]);
D3D :: stateman -> PushDepthState ( cleardepthstates [ 1 ]);
2016-01-11 01:31:00 +01:00
D3D11_VIEWPORT vp = CD3D11_VIEWPORT ( 0.0f , 0.0f , ( float ) GetTargetWidth (), ( float ) GetTargetHeight ());
2015-12-19 15:45:21 +10:00
2015-06-07 13:32:43 +02:00
D3D :: context -> RSSetViewports ( 1 , & vp );
D3D :: context -> OMSetRenderTargets ( 1 , & FramebufferManager :: GetEFBColorTexture () -> GetRTV (),
FramebufferManager :: GetEFBDepthTexture () -> GetDSV ());
}
2015-12-20 00:34:56 +10:00
D3D :: DrawEFBPokeQuads ( type , points , num_points );
2010-06-13 19:50:06 +00:00
2015-12-19 15:45:21 +10:00
if ( type == POKE_Z )
{
D3D :: stateman -> PopDepthState ();
D3D :: stateman -> PopBlendState ();
}
RestoreAPIState ();
}
2011-05-12 02:14:45 +00:00
2014-02-04 10:45:38 +01:00
void Renderer :: SetViewport ()
2010-06-13 19:50:06 +00:00
{
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
// [0] = width/2
// [1] = height/2
// [2] = 16777215 * (farz - nearz)
// [3] = xorig + width/2 + 342
// [4] = yorig + height/2 + 342
// [5] = 16777215 * farz
2010-07-11 16:26:46 +00:00
2014-02-15 18:57:55 +01:00
// D3D crashes for zero viewports
2014-04-27 11:59:04 -07:00
if ( xfmem . viewport . wd == 0 || xfmem . viewport . ht == 0 )
2014-02-15 18:57:55 +01:00
return ;
2011-05-12 02:14:45 +00:00
int scissorXOff = bpmem . scissorOffset . x * 2 ;
int scissorYOff = bpmem . scissorOffset . y * 2 ;
2010-06-13 19:50:06 +00:00
2014-04-27 11:59:04 -07:00
float X = Renderer :: EFBToScaledXf ( xfmem . viewport . xOrig - xfmem . viewport . wd - scissorXOff );
float Y = Renderer :: EFBToScaledYf ( xfmem . viewport . yOrig + xfmem . viewport . ht - scissorYOff );
float Wd = Renderer :: EFBToScaledXf ( 2.0f * xfmem . viewport . wd );
float Ht = Renderer :: EFBToScaledYf ( - 2.0f * xfmem . viewport . ht );
2013-10-14 15:16:42 +02:00
if ( Wd < 0.0f )
2010-06-13 19:50:06 +00:00
{
2013-10-14 15:16:42 +02:00
X += Wd ;
Wd = - Wd ;
2010-06-13 19:50:06 +00:00
}
2013-10-14 15:16:42 +02:00
if ( Ht < 0.0f )
2010-06-13 19:50:06 +00:00
{
2013-10-14 15:16:42 +02:00
Y += Ht ;
Ht = - Ht ;
2010-06-13 19:50:06 +00:00
}
2011-05-12 02:14:45 +00:00
// In D3D, the viewport rectangle must fit within the render target.
2013-10-14 15:16:42 +02:00
X = ( X >= 0.f ) ? X : 0.f ;
Y = ( Y >= 0.f ) ? Y : 0.f ;
Wd = ( X + Wd <= GetTargetWidth ()) ? Wd : ( GetTargetWidth () - X );
Ht = ( Y + Ht <= GetTargetHeight ()) ? Ht : ( GetTargetHeight () - Y );
2010-06-13 19:50:06 +00:00
2014-02-16 23:51:41 -05:00
D3D11_VIEWPORT vp = CD3D11_VIEWPORT ( X , Y , Wd , Ht ,
2015-05-24 14:44:25 +02:00
1.0f - MathUtil :: Clamp < float > ( xfmem . viewport . farZ , 0.0f , 16777215.0f ) / 16777216.0f ,
2016-01-03 15:39:34 +01:00
1.0f - MathUtil :: Clamp < float > ( xfmem . viewport . farZ - MathUtil :: Clamp < float > ( xfmem . viewport . zRange , 0.0f , 16777216.0f ), 0.0f , 16777215.0f ) / 16777216.0f );
2011-06-11 19:37:21 +00:00
D3D :: context -> RSSetViewports ( 1 , & vp );
2010-06-13 19:50:06 +00:00
}
2010-09-28 02:15:02 +00:00
2010-12-19 22:00:25 +00:00
void Renderer :: ClearScreen ( const EFBRectangle & rc , bool colorEnable , bool alphaEnable , bool zEnable , u32 color , u32 z )
2010-06-16 10:12:57 +00:00
{
2010-10-24 16:53:33 +00:00
ResetAPIState ();
2010-12-20 16:57:29 +00:00
if ( colorEnable && alphaEnable ) D3D :: stateman -> PushBlendState ( clearblendstates [ 0 ]);
else if ( colorEnable ) D3D :: stateman -> PushBlendState ( clearblendstates [ 1 ]);
else if ( alphaEnable ) D3D :: stateman -> PushBlendState ( clearblendstates [ 2 ]);
2010-10-24 16:53:33 +00:00
else D3D :: stateman -> PushBlendState ( clearblendstates [ 3 ]);
2010-10-20 02:29:20 +00:00
2010-12-20 16:57:29 +00:00
// TODO: Should we enable Z testing here?
/*if (!bpmem.zmode.testenable) D3D::stateman->PushDepthState(cleardepthstates[0]);
else */ if ( zEnable ) D3D :: stateman -> PushDepthState ( cleardepthstates [ 1 ]);
else /*if (!zEnable)*/ D3D :: stateman -> PushDepthState ( cleardepthstates [ 2 ]);
2010-11-01 19:13:50 +00:00
// Update the view port for clearing the picture
TargetRectangle targetRc = Renderer :: ConvertEFBRectangle ( rc );
2013-10-29 01:23:17 -04:00
D3D11_VIEWPORT vp = CD3D11_VIEWPORT (( float ) targetRc . left , ( float ) targetRc . top , ( float ) targetRc . GetWidth (), ( float ) targetRc . GetHeight (), 0.f , 1.f );
2011-06-11 19:37:21 +00:00
D3D :: context -> RSSetViewports ( 1 , & vp );
2010-11-01 19:13:50 +00:00
// Color is passed in bgra mode so we need to convert it to rgba
u32 rgbaColor = ( color & 0xFF00FF00 ) | (( color >> 16 ) & 0xFF ) | (( color << 16 ) & 0xFF0000 );
2015-05-24 14:44:25 +02:00
D3D :: drawClearQuad ( rgbaColor , 1.0f - ( z & 0xFFFFFF ) / 16777216.0f );
2010-10-20 02:29:20 +00:00
D3D :: stateman -> PopDepthState ();
2010-11-01 19:13:50 +00:00
D3D :: stateman -> PopBlendState ();
2010-10-20 02:29:20 +00:00
2010-10-24 16:53:33 +00:00
RestoreAPIState ();
2010-06-13 19:50:06 +00:00
}
2010-12-27 21:56:20 +00:00
void Renderer :: ReinterpretPixelData ( unsigned int convtype )
{
2011-02-04 17:00:34 +00:00
// TODO: MSAA support..
2011-05-12 02:14:45 +00:00
D3D11_RECT source = CD3D11_RECT ( 0 , 0 , g_renderer -> GetTargetWidth (), g_renderer -> GetTargetHeight ());
2011-02-04 17:00:34 +00:00
ID3D11PixelShader * pixel_shader ;
2011-04-30 14:08:58 +00:00
if ( convtype == 0 ) pixel_shader = PixelShaderCache :: ReinterpRGB8ToRGBA6 ( true );
else if ( convtype == 2 ) pixel_shader = PixelShaderCache :: ReinterpRGBA6ToRGB8 ( true );
2011-02-04 17:00:34 +00:00
else
{
2012-01-06 13:45:51 +01:00
ERROR_LOG ( VIDEO , "Trying to reinterpret pixel data with unsupported conversion type %d" , convtype );
2011-02-04 17:00:34 +00:00
return ;
}
// convert data and set the target texture as our new EFB
g_renderer -> ResetAPIState ();
2011-05-12 02:14:45 +00:00
D3D11_VIEWPORT vp = CD3D11_VIEWPORT ( 0.f , 0.f , ( float ) g_renderer -> GetTargetWidth (), ( float ) g_renderer -> GetTargetHeight ());
2011-06-11 19:37:21 +00:00
D3D :: context -> RSSetViewports ( 1 , & vp );
2011-02-04 17:00:34 +00:00
2014-03-09 21:14:26 +01:00
D3D :: context -> OMSetRenderTargets ( 1 , & FramebufferManager :: GetEFBColorTempTexture () -> GetRTV (), nullptr );
2011-02-04 17:00:34 +00:00
D3D :: SetPointCopySampler ();
2014-12-23 12:33:45 +01:00
D3D :: drawShadedTexQuad ( FramebufferManager :: GetEFBColorTexture () -> GetSRV (), & source , g_renderer -> GetTargetWidth (), g_renderer -> GetTargetHeight (),
pixel_shader , VertexShaderCache :: GetSimpleVertexShader (), VertexShaderCache :: GetSimpleInputLayout (), GeometryShaderCache :: GetCopyGeometryShader ());
2011-02-04 17:00:34 +00:00
g_renderer -> RestoreAPIState ();
FramebufferManager :: SwapReinterpretTexture ();
2011-06-11 19:37:21 +00:00
D3D :: context -> OMSetRenderTargets ( 1 , & FramebufferManager :: GetEFBColorTexture () -> GetRTV (), FramebufferManager :: GetEFBDepthTexture () -> GetDSV ());
2010-12-27 21:56:20 +00:00
}
2010-06-13 19:50:06 +00:00
void Renderer :: SetBlendMode ( bool forceUpdate )
{
2013-01-13 23:35:07 +01:00
// Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
// Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
2014-03-23 21:44:23 +01:00
bool target_has_alpha = bpmem . zcontrol . pixel_format == PEControl :: RGBA6_Z24 ;
2013-01-13 23:35:07 +01:00
const D3D11_BLEND d3dSrcFactors [ 8 ] =
{
D3D11_BLEND_ZERO ,
D3D11_BLEND_ONE ,
D3D11_BLEND_DEST_COLOR ,
D3D11_BLEND_INV_DEST_COLOR ,
D3D11_BLEND_SRC_ALPHA ,
D3D11_BLEND_INV_SRC_ALPHA , // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
( target_has_alpha ) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE ,
( target_has_alpha ) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO
};
const D3D11_BLEND d3dDestFactors [ 8 ] =
{
D3D11_BLEND_ZERO ,
D3D11_BLEND_ONE ,
D3D11_BLEND_SRC_COLOR ,
D3D11_BLEND_INV_SRC_COLOR ,
D3D11_BLEND_SRC_ALPHA ,
D3D11_BLEND_INV_SRC_ALPHA , // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
( target_has_alpha ) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE ,
( target_has_alpha ) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO
};
2014-12-15 20:08:54 -08:00
if ( bpmem . blendmode . logicopenable && ! bpmem . blendmode . blendenable && ! forceUpdate )
2010-06-13 19:50:06 +00:00
return ;
2013-03-28 22:59:42 +01:00
if ( bpmem . blendmode . subtract )
2010-06-13 19:50:06 +00:00
{
2014-06-05 13:58:36 +02:00
gx_state . blend . blend_enable = true ;
2014-10-17 22:24:44 +02:00
gx_state . blend . blend_op = D3D11_BLEND_OP_REV_SUBTRACT ;
gx_state . blend . src_blend = D3D11_BLEND_ONE ;
gx_state . blend . dst_blend = D3D11_BLEND_ONE ;
2010-06-13 19:50:06 +00:00
}
2010-09-28 02:15:02 +00:00
else
2010-06-13 19:50:06 +00:00
{
2014-06-09 11:55:25 +02:00
gx_state . blend . blend_enable = ( u32 ) bpmem . blendmode . blendenable ;
2013-01-13 23:35:07 +01:00
if ( bpmem . blendmode . blendenable )
2010-06-24 15:58:06 +00:00
{
2014-10-17 22:24:44 +02:00
gx_state . blend . blend_op = D3D11_BLEND_OP_ADD ;
gx_state . blend . src_blend = d3dSrcFactors [ bpmem . blendmode . srcfactor ];
gx_state . blend . dst_blend = d3dDestFactors [ bpmem . blendmode . dstfactor ];
2010-06-24 15:58:06 +00:00
}
2010-06-13 19:50:06 +00:00
}
}
2013-11-10 00:10:20 +01:00
bool Renderer :: SaveScreenshot ( const std :: string & filename , const TargetRectangle & rc )
2010-11-18 02:21:26 +00:00
{
2012-08-07 14:55:10 +02:00
if ( ! s_screenshot_texture )
2015-12-08 23:45:07 +10:00
CreateScreenshotTexture ();
2012-08-07 14:55:10 +02:00
2010-11-18 02:21:26 +00:00
// copy back buffer to system memory
2015-12-08 23:45:07 +10:00
D3D11_BOX source_box = GetScreenshotSourceBox ( rc );
D3D :: context -> CopySubresourceRegion ( s_screenshot_texture , 0 , 0 , 0 , 0 , ( ID3D11Resource * ) D3D :: GetBackBuffer () -> GetTex (), 0 , & source_box );
2010-11-18 02:21:26 +00:00
D3D11_MAPPED_SUBRESOURCE map ;
2011-09-08 15:39:03 +02:00
D3D :: context -> Map ( s_screenshot_texture , 0 , D3D11_MAP_READ_WRITE , 0 , & map );
2010-11-18 02:21:26 +00:00
2015-12-08 23:45:07 +10:00
bool saved_png = TextureToPng (( u8 * ) map . pData , map . RowPitch , filename , source_box . right - source_box . left , source_box . bottom - source_box . top , false );
2013-11-15 13:00:38 +13:00
2013-11-14 00:48:02 +13:00
D3D :: context -> Unmap ( s_screenshot_texture , 0 );
2013-11-15 13:00:38 +13:00
if ( saved_png )
2013-11-10 00:10:20 +01:00
{
OSD :: AddMessage ( StringFromFormat ( "Saved %i x %i %s" , rc . GetWidth (),
rc . GetHeight (), filename . c_str ()));
}
else
{
OSD :: AddMessage ( StringFromFormat ( "Error saving %s" , filename . c_str ()));
}
2013-11-15 13:00:38 +13:00
return saved_png ;
2010-11-18 02:21:26 +00:00
}
2013-02-26 20:47:48 -05:00
void formatBufferDump ( const u8 * in , u8 * out , int w , int h , int p )
2011-09-08 15:39:03 +02:00
{
for ( int y = 0 ; y < h ; ++ y )
{
2013-02-26 20:47:48 -05:00
auto line = ( in + ( h - y - 1 ) * p );
2011-09-08 15:39:03 +02:00
for ( int x = 0 ; x < w ; ++ x )
{
2011-09-08 17:52:01 +02:00
out [ 0 ] = line [ 2 ];
out [ 1 ] = line [ 1 ];
out [ 2 ] = line [ 0 ];
2011-09-08 15:39:03 +02:00
out += 3 ;
line += 4 ;
2011-09-08 17:52:01 +02:00
}
2011-09-08 15:39:03 +02:00
}
}
2010-11-18 02:21:26 +00:00
2010-09-28 02:15:02 +00:00
// This function has the final picture. We adjust the aspect ratio here.
2014-05-02 00:08:44 -07:00
void Renderer :: SwapImpl ( u32 xfbAddr , u32 fbWidth , u32 fbStride , u32 fbHeight , const EFBRectangle & rc , float Gamma )
2010-06-13 19:50:06 +00:00
{
2016-01-23 23:20:13 -05:00
if ( Fifo :: WillSkipCurrentFrame () || ( ! XFBWrited && ! g_ActiveConfig . RealXFBEnabled ()) || ! fbWidth || ! fbHeight )
2010-06-13 19:50:06 +00:00
{
2014-10-12 23:53:10 -04:00
if ( SConfig :: GetInstance (). m_DumpFrames && ! frame_data . empty ())
2013-02-26 20:47:48 -05:00
AVIDump :: AddFrame ( & frame_data [ 0 ], fbWidth , fbHeight );
2011-09-08 15:39:03 +02:00
2011-01-31 01:28:32 +00:00
Core :: Callback_VideoCopiedToXFB ( false );
2010-06-13 19:50:06 +00:00
return ;
}
2010-09-28 02:15:02 +00:00
2010-06-13 19:50:06 +00:00
u32 xfbCount = 0 ;
2014-10-14 22:21:36 -04:00
const XFBSourceBase * const * xfbSourceList = FramebufferManager :: GetXFBSource ( xfbAddr , fbStride , fbHeight , & xfbCount );
2010-07-02 17:09:53 +00:00
if (( ! xfbSourceList || xfbCount == 0 ) && g_ActiveConfig . bUseXFB && ! g_ActiveConfig . bUseRealXFB )
2010-06-13 19:50:06 +00:00
{
2014-10-12 23:53:10 -04:00
if ( SConfig :: GetInstance (). m_DumpFrames && ! frame_data . empty ())
2013-02-26 20:47:48 -05:00
AVIDump :: AddFrame ( & frame_data [ 0 ], fbWidth , fbHeight );
2011-09-08 15:39:03 +02:00
2011-01-31 01:28:32 +00:00
Core :: Callback_VideoCopiedToXFB ( false );
2010-06-13 19:50:06 +00:00
return ;
2010-06-16 10:12:57 +00:00
}
2010-06-13 19:50:06 +00:00
2010-11-18 02:21:26 +00:00
ResetAPIState ();
2010-06-21 17:54:13 +00:00
2010-09-28 02:15:02 +00:00
// Prepare to copy the XFBs to our backbuffer
2012-09-29 00:04:55 +02:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height );
2014-12-20 18:20:49 +01:00
TargetRectangle targetRc = GetTargetRectangle ();
2010-06-13 19:50:06 +00:00
2014-03-09 21:14:26 +01:00
D3D :: context -> OMSetRenderTargets ( 1 , & D3D :: GetBackBuffer () -> GetRTV (), nullptr );
2010-06-13 19:50:06 +00:00
2012-09-02 13:12:47 +02:00
float ClearColor [ 4 ] = { 0.f , 0.f , 0.f , 1.f };
D3D :: context -> ClearRenderTargetView ( D3D :: GetBackBuffer () -> GetRTV (), ClearColor );
2010-07-17 15:18:52 +00:00
// activate linear filtering for the buffer copies
D3D :: SetLinearCopySampler ();
2011-03-08 07:39:36 +00:00
if ( g_ActiveConfig . bUseXFB && g_ActiveConfig . bUseRealXFB )
{
// TODO: Television should be used to render Virtual XFB mode as well.
2014-12-20 18:20:49 +01:00
D3D11_VIEWPORT vp = CD3D11_VIEWPORT (( float ) targetRc . left , ( float ) targetRc . top , ( float ) targetRc . GetWidth (), ( float ) targetRc . GetHeight ());
D3D :: context -> RSSetViewports ( 1 , & vp );
2014-10-14 22:21:36 -04:00
s_television . Submit ( xfbAddr , fbStride , fbWidth , fbHeight );
2011-06-11 19:37:21 +00:00
s_television . Render ();
2011-03-08 07:39:36 +00:00
}
2014-03-11 00:30:55 +13:00
else if ( g_ActiveConfig . bUseXFB )
2010-06-13 19:50:06 +00:00
{
2014-12-20 18:20:49 +01:00
const XFBSource * xfbSource ;
2010-06-13 19:50:06 +00:00
2010-07-02 17:09:53 +00:00
// draw each xfb source
for ( u32 i = 0 ; i < xfbCount ; ++ i )
{
2014-12-20 18:20:49 +01:00
xfbSource = ( const XFBSource * ) xfbSourceList [ i ];
2013-10-29 01:23:17 -04:00
2014-12-20 18:20:49 +01:00
TargetRectangle drawRc ;
2010-06-13 19:50:06 +00:00
2014-12-24 23:54:43 +01:00
// use virtual xfb with offset
int xfbHeight = xfbSource -> srcHeight ;
int xfbWidth = xfbSource -> srcWidth ;
int hOffset = (( s32 ) xfbSource -> srcAddr - ( s32 ) xfbAddr ) / (( s32 ) fbStride * 2 );
2010-07-02 17:09:53 +00:00
2015-01-20 02:31:32 +10:30
drawRc . top = targetRc . top + hOffset * targetRc . GetHeight () / ( s32 ) fbHeight ;
drawRc . bottom = targetRc . top + ( hOffset + xfbHeight ) * targetRc . GetHeight () / ( s32 ) fbHeight ;
drawRc . left = targetRc . left + ( targetRc . GetWidth () - xfbWidth * targetRc . GetWidth () / ( s32 ) fbStride ) / 2 ;
drawRc . right = targetRc . left + ( targetRc . GetWidth () + xfbWidth * targetRc . GetWidth () / ( s32 ) fbStride ) / 2 ;
2010-07-02 17:09:53 +00:00
2014-12-24 23:54:43 +01:00
// The following code disables auto stretch. Kept for reference.
// scale draw area for a 1 to 1 pixel mapping with the draw target
//float vScale = (float)fbHeight / (float)s_backbuffer_height;
//float hScale = (float)fbWidth / (float)s_backbuffer_width;
//drawRc.top *= vScale;
//drawRc.bottom *= vScale;
//drawRc.left *= hScale;
//drawRc.right *= hScale;
2010-09-28 02:15:02 +00:00
2014-12-25 02:37:22 +01:00
TargetRectangle sourceRc ;
2015-11-28 20:04:36 +10:00
sourceRc . left = xfbSource -> sourceRc . left ;
sourceRc . top = xfbSource -> sourceRc . top ;
sourceRc . right = xfbSource -> sourceRc . right ;
sourceRc . bottom = xfbSource -> sourceRc . bottom ;
2014-12-20 18:20:49 +01:00
2015-01-03 22:05:22 +00:00
sourceRc . right -= Renderer :: EFBToScaledX ( fbStride - fbWidth );
2015-01-03 01:28:49 +00:00
2014-12-20 18:20:49 +01:00
BlitScreen ( sourceRc , drawRc , xfbSource -> tex , xfbSource -> texWidth , xfbSource -> texHeight , Gamma );
2010-07-02 17:09:53 +00:00
}
}
else
{
2014-12-20 18:20:49 +01:00
TargetRectangle sourceRc = Renderer :: ConvertEFBRectangle ( rc );
2010-11-27 11:11:05 +00:00
// TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB texture as source
2010-11-23 19:58:02 +00:00
D3DTexture2D * read_texture = FramebufferManager :: GetResolvedEFBColorTexture ();
2014-12-20 18:20:49 +01:00
BlitScreen ( sourceRc , targetRc , read_texture , GetTargetWidth (), GetTargetHeight (), Gamma );
2010-06-13 19:50:06 +00:00
}
2011-03-08 07:39:36 +00:00
2010-06-21 17:54:13 +00:00
// done with drawing the game stuff, good moment to save a screenshot
2010-06-17 10:42:57 +00:00
if ( s_bScreenshot )
{
2015-12-08 23:45:07 +10:00
std :: lock_guard < std :: mutex > guard ( s_criticalScreenshot );
2013-11-10 00:10:20 +01:00
SaveScreenshot ( s_sScreenshotName , GetTargetRectangle ());
2015-12-08 23:45:07 +10:00
s_sScreenshotName . clear ();
2013-11-02 22:42:46 -04:00
s_bScreenshot = false ;
2015-12-08 23:45:07 +10:00
s_screenshotCompleted . Set ();
2010-06-17 10:42:57 +00:00
}
2010-06-13 19:50:06 +00:00
2011-09-08 15:39:03 +02:00
// Dump frames
static int w = 0 , h = 0 ;
2014-10-12 23:53:10 -04:00
if ( SConfig :: GetInstance (). m_DumpFrames )
2011-09-08 15:39:03 +02:00
{
static int s_recordWidth ;
static int s_recordHeight ;
2012-08-07 14:55:10 +02:00
if ( ! s_screenshot_texture )
2015-12-08 23:45:07 +10:00
CreateScreenshotTexture ();
2012-08-07 14:55:10 +02:00
2015-12-08 23:45:07 +10:00
D3D11_BOX source_box = GetScreenshotSourceBox ( targetRc );
unsigned int source_width = source_box . right - source_box . left ;
unsigned int source_height = source_box . bottom - source_box . top ;
D3D :: context -> CopySubresourceRegion ( s_screenshot_texture , 0 , 0 , 0 , 0 , ( ID3D11Resource * ) D3D :: GetBackBuffer () -> GetTex (), 0 , & source_box );
2011-09-08 15:39:03 +02:00
if ( ! bLastFrameDumped )
{
2015-12-08 23:45:07 +10:00
s_recordWidth = source_width ;
s_recordHeight = source_height ;
2016-01-01 08:50:15 -06:00
bAVIDumping = AVIDump :: Start ( s_recordWidth , s_recordHeight , AVIDump :: DumpFormat :: FORMAT_BGR );
2011-09-08 17:09:24 +02:00
if ( ! bAVIDumping )
2011-09-08 15:39:03 +02:00
{
PanicAlert ( "Error dumping frames to AVI." );
}
else
{
2014-05-25 20:52:58 -04:00
std :: string msg = StringFromFormat ( "Dumping Frames to \" %sframedump0.avi \" (%dx%d RGB24)" ,
File :: GetUserPath ( D_DUMPFRAMES_IDX ). c_str (), s_recordWidth , s_recordHeight );
2011-09-08 15:39:03 +02:00
OSD :: AddMessage ( msg , 2000 );
}
}
2011-09-08 17:09:24 +02:00
if ( bAVIDumping )
2011-09-08 15:39:03 +02:00
{
D3D11_MAPPED_SUBRESOURCE map ;
D3D :: context -> Map ( s_screenshot_texture , 0 , D3D11_MAP_READ , 0 , & map );
2013-02-26 20:47:48 -05:00
if ( frame_data . empty () || w != s_recordWidth || h != s_recordHeight )
2011-09-08 15:39:03 +02:00
{
2013-02-26 20:47:48 -05:00
frame_data . resize ( 3 * s_recordWidth * s_recordHeight );
2011-09-08 15:39:03 +02:00
w = s_recordWidth ;
h = s_recordHeight ;
}
2015-12-08 23:45:07 +10:00
formatBufferDump (( u8 * ) map . pData , & frame_data [ 0 ], source_width , source_height , map . RowPitch );
2016-01-02 13:07:08 -05:00
FlipImageData ( & frame_data [ 0 ], w , h );
2015-12-08 23:45:07 +10:00
AVIDump :: AddFrame ( & frame_data [ 0 ], source_width , source_height );
2011-09-08 15:39:03 +02:00
D3D :: context -> Unmap ( s_screenshot_texture , 0 );
}
bLastFrameDumped = true ;
}
else
{
2011-09-08 17:09:24 +02:00
if ( bLastFrameDumped && bAVIDumping )
2011-09-08 15:39:03 +02:00
{
2013-02-26 20:47:48 -05:00
std :: vector < u8 > (). swap ( frame_data );
2011-09-08 15:39:03 +02:00
w = h = 0 ;
AVIDump :: Stop ();
2011-09-08 17:09:24 +02:00
bAVIDumping = false ;
2011-09-08 15:39:03 +02:00
OSD :: AddMessage ( "Stop dumping frames to AVI" , 2000 );
}
bLastFrameDumped = false ;
}
2014-06-16 23:34:07 +02:00
// Reset viewport for drawing text
2014-12-20 18:20:49 +01:00
D3D11_VIEWPORT vp = CD3D11_VIEWPORT ( 0.0f , 0.0f , ( float ) GetBackbufferWidth (), ( float ) GetBackbufferHeight ());
2014-06-16 23:34:07 +02:00
D3D :: context -> RSSetViewports ( 1 , & vp );
2010-06-13 19:50:06 +00:00
Renderer :: DrawDebugText ();
2014-11-19 19:57:12 +01:00
2010-06-13 19:50:06 +00:00
OSD :: DrawMessages ();
D3D :: EndFrame ();
2010-12-05 14:15:36 +00:00
2015-11-06 01:28:05 +01:00
TextureCacheBase :: Cleanup ( frameCount );
2010-06-13 19:50:06 +00:00
2011-12-26 22:04:59 +01:00
// Enable configuration changes
2010-06-13 19:50:06 +00:00
UpdateActiveConfig ();
2015-11-06 01:28:05 +01:00
TextureCacheBase :: OnConfigChanged ( g_ActiveConfig );
2011-01-07 04:57:59 +00:00
2014-10-14 22:21:36 -04:00
SetWindowSize ( fbStride , fbHeight );
2011-01-07 04:57:59 +00:00
const bool windowResized = CheckForResize ();
2015-01-17 13:49:02 +01:00
const bool fullscreen = g_ActiveConfig . bFullscreen && ! g_ActiveConfig . bBorderlessFullscreen &&
2015-06-12 13:56:53 +02:00
! SConfig :: GetInstance (). bRenderToMain ;
2014-07-10 22:43:15 +02:00
2014-12-28 18:26:25 +01:00
bool xfbchanged = s_last_xfb_mode != g_ActiveConfig . bUseRealXFB ;
2010-09-28 02:15:02 +00:00
2014-10-14 22:21:36 -04:00
if ( FramebufferManagerBase :: LastXfbWidth () != fbStride || FramebufferManagerBase :: LastXfbHeight () != fbHeight )
2010-06-13 19:50:06 +00:00
{
xfbchanged = true ;
2015-03-15 19:28:47 -07:00
unsigned int xfb_w = ( fbStride < 1 || fbStride > MAX_XFB_WIDTH ) ? MAX_XFB_WIDTH : fbStride ;
unsigned int xfb_h = ( fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT ) ? MAX_XFB_HEIGHT : fbHeight ;
FramebufferManagerBase :: SetLastXfbWidth ( xfb_w );
FramebufferManagerBase :: SetLastXfbHeight ( xfb_h );
2010-06-13 19:50:06 +00:00
}
2010-09-28 02:15:02 +00:00
// Flip/present backbuffer to frontbuffer here
2010-06-13 19:50:06 +00:00
D3D :: Present ();
2010-06-21 17:54:13 +00:00
2015-01-04 16:33:58 +01:00
// Check exclusive fullscreen state
2015-01-05 00:01:22 +01:00
bool exclusive_mode , fullscreen_changed = false ;
if ( SUCCEEDED ( D3D :: GetFullscreenState ( & exclusive_mode )))
2015-01-04 16:33:58 +01:00
{
2015-01-05 00:01:22 +01:00
if ( fullscreen && ! exclusive_mode )
2015-01-04 16:33:58 +01:00
{
2015-01-18 04:35:08 +01:00
if ( g_Config . bExclusiveMode )
2015-01-17 04:23:48 +01:00
OSD :: AddMessage ( "Lost exclusive fullscreen." );
2015-01-05 00:01:22 +01:00
// Exclusive fullscreen is enabled in the configuration, but we're
// not in exclusive mode. Either exclusive fullscreen was turned on
// or the render frame lost focus. When the render frame is in focus
// we can apply exclusive mode.
2015-01-04 16:33:58 +01:00
fullscreen_changed = Host_RendererHasFocus ();
2015-01-18 04:35:08 +01:00
g_Config . bExclusiveMode = false ;
2015-01-04 16:33:58 +01:00
}
2015-01-16 16:01:29 +01:00
else if ( ! fullscreen && exclusive_mode )
2015-01-05 00:01:22 +01:00
{
2015-01-16 16:01:29 +01:00
// Exclusive fullscreen is disabled, but we're still in exclusive mode.
fullscreen_changed = true ;
2015-01-05 00:01:22 +01:00
}
2015-01-04 16:33:58 +01:00
}
2014-07-26 12:43:49 +02:00
// Resize the back buffers NOW to avoid flickering
2015-07-20 20:12:29 -04:00
if ( CalculateTargetSize ( s_backbuffer_width , s_backbuffer_height ) ||
xfbchanged ||
2011-01-07 04:57:59 +00:00
windowResized ||
2014-07-16 22:13:13 +02:00
fullscreen_changed ||
2014-12-28 18:35:23 +01:00
s_last_efb_scale != g_ActiveConfig . iEFBScale ||
2015-12-12 13:00:08 +01:00
s_last_multisamples != g_ActiveConfig . iMultisamples ||
2014-12-28 18:35:23 +01:00
s_last_stereo_mode != ( g_ActiveConfig . iStereoMode > 0 ))
2010-06-18 14:55:18 +00:00
{
2014-12-28 18:26:25 +01:00
s_last_xfb_mode = g_ActiveConfig . bUseRealXFB ;
2015-12-12 13:00:08 +01:00
s_last_multisamples = g_ActiveConfig . iMultisamples ;
2010-11-27 11:11:05 +00:00
PixelShaderCache :: InvalidateMSAAShaders ();
2010-11-23 19:58:02 +00:00
2014-07-16 22:13:13 +02:00
if ( windowResized || fullscreen_changed )
2012-08-07 14:55:10 +02:00
{
2014-07-26 12:43:49 +02:00
// Apply fullscreen state
2014-07-16 15:53:33 +02:00
if ( fullscreen_changed )
2015-01-16 16:01:29 +01:00
{
2015-01-18 04:35:08 +01:00
g_Config . bExclusiveMode = fullscreen ;
2015-01-17 04:23:48 +01:00
if ( fullscreen )
OSD :: AddMessage ( "Entered exclusive fullscreen." );
2014-07-26 13:00:49 +02:00
D3D :: SetFullscreenState ( fullscreen );
2014-07-21 20:10:54 +02:00
2015-01-17 13:49:02 +01:00
// If fullscreen is disabled we can safely notify the UI to exit fullscreen.
if ( ! g_ActiveConfig . bFullscreen )
2015-01-16 16:01:29 +01:00
Host_RequestFullscreen ( false );
}
2012-08-07 14:55:10 +02:00
// TODO: Aren't we still holding a reference to the back buffer right now?
D3D :: Reset ();
SAFE_RELEASE ( s_screenshot_texture );
2014-11-14 00:24:53 +01:00
SAFE_RELEASE ( s_3d_vision_texture );
2012-08-07 14:55:10 +02:00
s_backbuffer_width = D3D :: GetBackBufferWidth ();
s_backbuffer_height = D3D :: GetBackBufferHeight ();
}
2010-06-18 14:55:18 +00:00
2012-09-29 00:04:55 +02:00
UpdateDrawRectangle ( s_backbuffer_width , s_backbuffer_height );
2010-06-18 14:55:18 +00:00
2014-12-28 18:35:23 +01:00
s_last_efb_scale = g_ActiveConfig . iEFBScale ;
s_last_stereo_mode = g_ActiveConfig . iStereoMode > 0 ;
2010-06-18 14:55:18 +00:00
2015-01-03 06:06:56 +13:00
PixelShaderManager :: SetEfbScaleChanged ();
2014-03-09 21:14:26 +01:00
D3D :: context -> OMSetRenderTargets ( 1 , & D3D :: GetBackBuffer () -> GetRTV (), nullptr );
2012-08-07 14:55:10 +02:00
2015-12-23 23:06:47 +10:00
g_framebuffer_manager . reset ();
2015-12-22 18:47:20 -05:00
g_framebuffer_manager = std :: make_unique < FramebufferManager > ();
2010-12-21 22:18:40 +00:00
float clear_col [ 4 ] = { 0.f , 0.f , 0.f , 1.f };
2011-06-11 19:37:21 +00:00
D3D :: context -> ClearRenderTargetView ( FramebufferManager :: GetEFBColorTexture () -> GetRTV (), clear_col );
2015-05-25 23:29:47 +02:00
D3D :: context -> ClearDepthStencilView ( FramebufferManager :: GetEFBDepthTexture () -> GetDSV (), D3D11_CLEAR_DEPTH , 0.f , 0 );
2010-06-18 14:55:18 +00:00
}
2010-06-21 17:54:13 +00:00
// begin next frame
2013-10-15 00:05:49 +02:00
RestoreAPIState ();
2010-06-21 17:54:13 +00:00
D3D :: BeginFrame ();
2011-06-11 19:37:21 +00:00
D3D :: context -> OMSetRenderTargets ( 1 , & FramebufferManager :: GetEFBColorTexture () -> GetRTV (), FramebufferManager :: GetEFBDepthTexture () -> GetDSV ());
2014-02-04 10:45:38 +01:00
SetViewport ();
2010-06-13 19:50:06 +00:00
}
2010-06-21 17:54:13 +00:00
// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
2010-06-13 19:50:06 +00:00
void Renderer :: ResetAPIState ()
{
2010-06-18 23:33:07 +00:00
D3D :: stateman -> PushBlendState ( resetblendstate );
D3D :: stateman -> PushDepthState ( resetdepthstate );
D3D :: stateman -> PushRasterizerState ( resetraststate );
2010-06-13 19:50:06 +00:00
}
void Renderer :: RestoreAPIState ()
{
2010-09-28 02:15:02 +00:00
// Gets us back into a more game-like state.
2011-01-27 10:17:13 +00:00
D3D :: stateman -> PopBlendState ();
D3D :: stateman -> PopDepthState ();
D3D :: stateman -> PopRasterizerState ();
2014-02-04 10:45:38 +01:00
SetViewport ();
2011-09-05 22:04:28 +02:00
BPFunctions :: SetScissor ();
2010-06-13 19:50:06 +00:00
}
2012-08-10 18:57:37 +02:00
void Renderer :: ApplyState ( bool bUseDstAlpha )
2011-01-24 08:44:32 +00:00
{
2014-06-05 13:58:36 +02:00
gx_state . blend . use_dst_alpha = bUseDstAlpha ;
D3D :: stateman -> PushBlendState ( gx_state_cache . Get ( gx_state . blend ));
D3D :: stateman -> PushDepthState ( gx_state_cache . Get ( gx_state . zmode ));
D3D :: stateman -> PushRasterizerState ( gx_state_cache . Get ( gx_state . raster ));
2011-01-24 09:27:16 +00:00
2011-01-24 08:44:32 +00:00
for ( unsigned int stage = 0 ; stage < 8 ; stage ++ )
{
2014-10-29 01:19:09 +01:00
// TODO: cache SamplerState directly, not d3d object
2016-03-30 20:45:40 -04:00
gx_state . sampler [ stage ]. max_anisotropy = UINT64_C ( 1 ) << g_ActiveConfig . iMaxAnisotropy ;
2014-12-06 14:54:06 +01:00
D3D :: stateman -> SetSampler ( stage , gx_state_cache . Get ( gx_state . sampler [ stage ]));
2011-01-24 08:44:32 +00:00
}
2011-01-24 10:42:43 +00:00
2012-08-10 18:57:37 +02:00
if ( bUseDstAlpha )
2011-01-24 10:42:43 +00:00
{
// restore actual state
SetBlendMode ( false );
SetLogicOpMode ();
}
2011-01-24 11:57:17 +00:00
2014-10-29 01:19:09 +01:00
ID3D11Buffer * vertexConstants = VertexShaderCache :: GetConstantBuffer ();
2011-01-25 15:08:30 +00:00
2014-12-17 03:05:23 +01:00
D3D :: stateman -> SetPixelConstants ( PixelShaderCache :: GetConstantBuffer (), g_ActiveConfig . bEnablePixelLighting ? vertexConstants : nullptr );
2014-12-06 14:54:06 +01:00
D3D :: stateman -> SetVertexConstants ( vertexConstants );
2014-12-17 03:05:23 +01:00
D3D :: stateman -> SetGeometryConstants ( GeometryShaderCache :: GetConstantBuffer ());
2014-10-29 01:19:09 +01:00
2014-12-06 14:54:06 +01:00
D3D :: stateman -> SetPixelShader ( PixelShaderCache :: GetActiveShader ());
D3D :: stateman -> SetVertexShader ( VertexShaderCache :: GetActiveShader ());
2014-12-17 03:05:23 +01:00
D3D :: stateman -> SetGeometryShader ( GeometryShaderCache :: GetActiveShader ());
2011-01-24 08:44:32 +00:00
}
2012-03-30 01:56:24 +02:00
void Renderer :: RestoreState ()
2011-01-24 08:44:32 +00:00
{
2011-01-24 10:42:43 +00:00
D3D :: stateman -> PopBlendState ();
2011-01-24 09:10:35 +00:00
D3D :: stateman -> PopDepthState ();
2011-01-24 09:27:16 +00:00
D3D :: stateman -> PopRasterizerState ();
2011-01-24 08:44:32 +00:00
}
2011-03-15 03:51:31 +00:00
void Renderer :: ApplyCullDisable ()
{
2014-06-05 13:58:36 +02:00
RasterizerState rast = gx_state . raster ;
rast . cull_mode = D3D11_CULL_NONE ;
2011-03-15 03:51:31 +00:00
2014-06-05 13:58:36 +02:00
ID3D11RasterizerState * raststate = gx_state_cache . Get ( rast );
2011-03-15 03:51:31 +00:00
D3D :: stateman -> PushRasterizerState ( raststate );
}
void Renderer :: RestoreCull ()
{
D3D :: stateman -> PopRasterizerState ();
}
2010-06-13 19:50:06 +00:00
void Renderer :: SetGenerationMode ()
{
2013-01-13 23:35:07 +01:00
const D3D11_CULL_MODE d3dCullModes [ 4 ] =
{
D3D11_CULL_NONE ,
D3D11_CULL_BACK ,
D3D11_CULL_FRONT ,
D3D11_CULL_BACK
};
2011-01-24 09:27:16 +00:00
// rastdc.FrontCounterClockwise must be false for this to work
2013-12-30 20:37:59 +01:00
// TODO: GX_CULL_ALL not supported, yet!
2014-06-05 13:58:36 +02:00
gx_state . raster . cull_mode = d3dCullModes [ bpmem . genMode . cullmode ];
2010-06-13 19:50:06 +00:00
}
void Renderer :: SetDepthMode ()
{
2015-09-03 21:53:45 -04:00
gx_state . zmode . hex = bpmem . zmode . hex ;
2010-06-13 19:50:06 +00:00
}
void Renderer :: SetLogicOpMode ()
{
2013-01-13 23:35:07 +01:00
// D3D11 doesn't support logic blending, so this is a huge hack
// TODO: Make use of D3D11.1's logic blending support
2014-02-16 15:30:18 -05:00
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
2013-01-13 23:35:07 +01:00
const D3D11_BLEND_OP d3dLogicOps [ 16 ] =
{
D3D11_BLEND_OP_ADD , //0
D3D11_BLEND_OP_ADD , //1
D3D11_BLEND_OP_SUBTRACT , //2
D3D11_BLEND_OP_ADD , //3
D3D11_BLEND_OP_REV_SUBTRACT , //4
D3D11_BLEND_OP_ADD , //5
D3D11_BLEND_OP_MAX , //6
D3D11_BLEND_OP_ADD , //7
D3D11_BLEND_OP_MAX , //8
D3D11_BLEND_OP_MAX , //9
D3D11_BLEND_OP_ADD , //10
D3D11_BLEND_OP_ADD , //11
D3D11_BLEND_OP_ADD , //12
D3D11_BLEND_OP_ADD , //13
D3D11_BLEND_OP_ADD , //14
D3D11_BLEND_OP_ADD //15
};
const D3D11_BLEND d3dLogicOpSrcFactors [ 16 ] =
{
D3D11_BLEND_ZERO , //0
D3D11_BLEND_DEST_COLOR , //1
D3D11_BLEND_ONE , //2
D3D11_BLEND_ONE , //3
D3D11_BLEND_DEST_COLOR , //4
D3D11_BLEND_ZERO , //5
D3D11_BLEND_INV_DEST_COLOR , //6
D3D11_BLEND_INV_DEST_COLOR , //7
D3D11_BLEND_INV_SRC_COLOR , //8
D3D11_BLEND_INV_SRC_COLOR , //9
D3D11_BLEND_INV_DEST_COLOR , //10
D3D11_BLEND_ONE , //11
D3D11_BLEND_INV_SRC_COLOR , //12
2013-10-29 01:23:17 -04:00
D3D11_BLEND_INV_SRC_COLOR , //13
2013-01-13 23:35:07 +01:00
D3D11_BLEND_INV_DEST_COLOR , //14
D3D11_BLEND_ONE //15
};
const D3D11_BLEND d3dLogicOpDestFactors [ 16 ] =
{
D3D11_BLEND_ZERO , //0
D3D11_BLEND_ZERO , //1
D3D11_BLEND_INV_SRC_COLOR , //2
D3D11_BLEND_ZERO , //3
D3D11_BLEND_ONE , //4
D3D11_BLEND_ONE , //5
D3D11_BLEND_INV_SRC_COLOR , //6
D3D11_BLEND_ONE , //7
D3D11_BLEND_INV_DEST_COLOR , //8
D3D11_BLEND_SRC_COLOR , //9
D3D11_BLEND_INV_DEST_COLOR , //10
D3D11_BLEND_INV_DEST_COLOR , //11
D3D11_BLEND_INV_SRC_COLOR , //12
2013-10-29 01:23:17 -04:00
D3D11_BLEND_ONE , //13
2013-01-13 23:35:07 +01:00
D3D11_BLEND_INV_SRC_COLOR , //14
D3D11_BLEND_ONE //15
};
2014-12-15 20:08:54 -08:00
if ( bpmem . blendmode . logicopenable && ! bpmem . blendmode . blendenable )
2010-06-13 19:50:06 +00:00
{
2014-06-05 13:58:36 +02:00
gx_state . blend . blend_enable = true ;
2014-10-17 22:24:44 +02:00
gx_state . blend . blend_op = d3dLogicOps [ bpmem . blendmode . logicmode ];
gx_state . blend . src_blend = d3dLogicOpSrcFactors [ bpmem . blendmode . logicmode ];
gx_state . blend . dst_blend = d3dLogicOpDestFactors [ bpmem . blendmode . logicmode ];
2010-06-13 19:50:06 +00:00
}
else
{
SetBlendMode ( true );
}
}
void Renderer :: SetDitherMode ()
{
// TODO: Set dither mode to bpmem.blendmode.dither
}
2015-03-01 13:04:48 +01:00
void Renderer :: SetSamplerState ( int stage , int texindex , bool custom_tex )
2010-06-13 19:50:06 +00:00
{
2010-06-16 10:12:57 +00:00
const FourTexUnits & tex = bpmem . tex [ texindex ];
2010-06-13 19:50:06 +00:00
const TexMode0 & tm0 = tex . texMode0 [ stage ];
const TexMode1 & tm1 = tex . texMode1 [ stage ];
2013-10-29 01:23:17 -04:00
2014-02-16 15:30:18 -05:00
if ( texindex )
stage += 4 ;
2010-06-13 19:50:06 +00:00
2010-11-27 11:11:05 +00:00
if ( g_ActiveConfig . bForceFiltering )
{
2016-03-24 02:23:56 +00:00
// Only use mipmaps if the game says they are available.
2016-03-24 02:42:08 +00:00
gx_state . sampler [ stage ]. min_filter = SamplerCommon :: AreBpTexMode0MipmapsEnabled ( tm0 ) ? 6 : 4 ;
2014-06-05 13:58:36 +02:00
gx_state . sampler [ stage ]. mag_filter = 1 ; // linear mag
2010-11-27 11:11:05 +00:00
}
2014-06-05 13:58:36 +02:00
else
2010-06-13 19:50:06 +00:00
{
2014-06-09 11:55:25 +02:00
gx_state . sampler [ stage ]. min_filter = ( u32 ) tm0 . min_filter ;
gx_state . sampler [ stage ]. mag_filter = ( u32 ) tm0 . mag_filter ;
2010-06-13 19:50:06 +00:00
}
2014-06-09 11:55:25 +02:00
gx_state . sampler [ stage ]. wrap_s = ( u32 ) tm0 . wrap_s ;
gx_state . sampler [ stage ]. wrap_t = ( u32 ) tm0 . wrap_t ;
gx_state . sampler [ stage ]. max_lod = ( u32 ) tm1 . max_lod ;
gx_state . sampler [ stage ]. min_lod = ( u32 ) tm1 . min_lod ;
gx_state . sampler [ stage ]. lod_bias = ( s32 ) tm0 . lod_bias ;
2015-03-01 13:04:48 +01:00
// custom textures may have higher resolution, so disable the max_lod
if ( custom_tex )
{
gx_state . sampler [ stage ]. max_lod = 255 ;
}
2010-06-13 19:50:06 +00:00
}
void Renderer :: SetInterlacingMode ()
{
// TODO
}
2014-09-25 19:50:25 -04:00
int Renderer :: GetMaxTextureSize ()
{
return DX11 :: D3D :: GetMaxTextureSize ();
}
2014-12-04 23:01:20 -03:00
u16 Renderer :: BBoxRead ( int index )
{
// Here we get the min/max value of the truncated position of the upscaled framebuffer.
// So we have to correct them to the unscaled EFB sizes.
int value = BBox :: Get ( index );
if ( index < 2 )
{
// left/right
value = value * EFB_WIDTH / s_target_width ;
}
else
{
// up/down
value = value * EFB_HEIGHT / s_target_height ;
}
if ( index & 1 )
value ++ ; // fix max values to describe the outer border
return value ;
}
void Renderer :: BBoxWrite ( int index , u16 _value )
{
int value = _value ; // u16 isn't enough to multiply by the efb width
if ( index & 1 )
value -- ;
if ( index < 2 )
{
value = value * s_target_width / EFB_WIDTH ;
}
else
{
value = value * s_target_height / EFB_HEIGHT ;
}
BBox :: Set ( index , value );
}
2014-12-20 18:20:49 +01:00
void Renderer :: BlitScreen ( TargetRectangle src , TargetRectangle dst , D3DTexture2D * src_texture , u32 src_width , u32 src_height , float Gamma )
{
if ( g_ActiveConfig . iStereoMode == STEREO_SBS || g_ActiveConfig . iStereoMode == STEREO_TAB )
{
TargetRectangle leftRc , rightRc ;
ConvertStereoRectangle ( dst , leftRc , rightRc );
D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT (( float ) leftRc . left , ( float ) leftRc . top , ( float ) leftRc . GetWidth (), ( float ) leftRc . GetHeight ());
D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT (( float ) rightRc . left , ( float ) rightRc . top , ( float ) rightRc . GetWidth (), ( float ) rightRc . GetHeight ());
D3D :: context -> RSSetViewports ( 1 , & leftVp );
D3D :: drawShadedTexQuad ( src_texture -> GetSRV (), src . AsRECT (), src_width , src_height , PixelShaderCache :: GetColorCopyProgram ( false ), VertexShaderCache :: GetSimpleVertexShader (), VertexShaderCache :: GetSimpleInputLayout (), nullptr , Gamma , 0 );
D3D :: context -> RSSetViewports ( 1 , & rightVp );
D3D :: drawShadedTexQuad ( src_texture -> GetSRV (), src . AsRECT (), src_width , src_height , PixelShaderCache :: GetColorCopyProgram ( false ), VertexShaderCache :: GetSimpleVertexShader (), VertexShaderCache :: GetSimpleInputLayout (), nullptr , Gamma , 1 );
}
else if ( g_ActiveConfig . iStereoMode == STEREO_3DVISION )
{
if ( ! s_3d_vision_texture )
Create3DVisionTexture ( s_backbuffer_width , s_backbuffer_height );
D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT (( float ) dst . left , ( float ) dst . top , ( float ) dst . GetWidth (), ( float ) dst . GetHeight ());
D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT (( float )( dst . left + s_backbuffer_width ), ( float ) dst . top , ( float ) dst . GetWidth (), ( float ) dst . GetHeight ());
// Render to staging texture which is double the width of the backbuffer
D3D :: context -> OMSetRenderTargets ( 1 , & s_3d_vision_texture -> GetRTV (), nullptr );
D3D :: context -> RSSetViewports ( 1 , & leftVp );
D3D :: drawShadedTexQuad ( src_texture -> GetSRV (), src . AsRECT (), src_width , src_height , PixelShaderCache :: GetColorCopyProgram ( false ), VertexShaderCache :: GetSimpleVertexShader (), VertexShaderCache :: GetSimpleInputLayout (), nullptr , Gamma , 0 );
D3D :: context -> RSSetViewports ( 1 , & rightVp );
D3D :: drawShadedTexQuad ( src_texture -> GetSRV (), src . AsRECT (), src_width , src_height , PixelShaderCache :: GetColorCopyProgram ( false ), VertexShaderCache :: GetSimpleVertexShader (), VertexShaderCache :: GetSimpleInputLayout (), nullptr , Gamma , 1 );
// Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should
// recognize the signature and automatically include the right eye frame.
D3D11_BOX box = CD3D11_BOX ( 0 , 0 , 0 , s_backbuffer_width , s_backbuffer_height , 1 );
D3D :: context -> CopySubresourceRegion ( D3D :: GetBackBuffer () -> GetTex (), 0 , 0 , 0 , 0 , s_3d_vision_texture -> GetTex (), 0 , & box );
// Restore render target to backbuffer
D3D :: context -> OMSetRenderTargets ( 1 , & D3D :: GetBackBuffer () -> GetRTV (), nullptr );
}
else
{
D3D11_VIEWPORT vp = CD3D11_VIEWPORT (( float ) dst . left , ( float ) dst . top , ( float ) dst . GetWidth (), ( float ) dst . GetHeight ());
D3D :: context -> RSSetViewports ( 1 , & vp );
D3D :: drawShadedTexQuad ( src_texture -> GetSRV (), src . AsRECT (), src_width , src_height , ( g_Config . iStereoMode == STEREO_ANAGLYPH ) ? PixelShaderCache :: GetAnaglyphProgram () : PixelShaderCache :: GetColorCopyProgram ( false ), VertexShaderCache :: GetSimpleVertexShader (), VertexShaderCache :: GetSimpleInputLayout (), nullptr , Gamma );
}
}
2012-01-06 13:45:51 +01:00
} // namespace DX11