2017-02-08 18:07:34 +01:00
// Copyright (c) 2017- PPSSPP 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 or later versions.
// 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 git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2017-02-23 11:26:16 +01:00
# include <d3d11.h>
# include <D3Dcompiler.h>
2017-03-07 13:00:59 +01:00
# include "base/display.h"
2017-02-08 18:07:34 +01:00
# include "math/lin/matrix4x4.h"
# include "ext/native/thin3d/thin3d.h"
2017-02-12 11:20:55 +01:00
# include "base/basictypes.h"
2017-02-16 16:37:34 +01:00
# include "file/vfs.h"
# include "file/zip_read.h"
2017-02-23 12:41:22 +01:00
# include "i18n/i18n.h"
2017-02-08 18:07:34 +01:00
# include "Common/ColorConv.h"
2017-02-16 16:37:34 +01:00
# include "Common/MathUtil.h"
2017-02-08 18:07:34 +01:00
# include "Core/Host.h"
# include "Core/MemMap.h"
# include "Core/Config.h"
# include "Core/System.h"
# include "Core/Reporting.h"
# include "GPU/ge_constants.h"
# include "GPU/GPUState.h"
# include "GPU/Debugger/Stepping.h"
# include "GPU/Common/FramebufferCommon.h"
2017-02-16 16:37:34 +01:00
# include "GPU/Common/ShaderTranslation.h"
2017-02-08 18:07:34 +01:00
# include "GPU/Common/TextureDecoder.h"
2017-02-16 16:37:34 +01:00
# include "GPU/Common/PostShader.h"
2017-02-08 18:07:34 +01:00
# include "GPU/D3D11/FramebufferManagerD3D11.h"
# include "GPU/D3D11/ShaderManagerD3D11.h"
# include "GPU/D3D11/TextureCacheD3D11.h"
# include "GPU/D3D11/DrawEngineD3D11.h"
2017-02-23 12:41:22 +01:00
# include "UI/OnScreenDisplay.h"
2017-02-08 18:07:34 +01:00
# include "ext/native/thin3d/thin3d.h"
# include <algorithm>
# ifdef _M_SSE
2017-03-12 17:16:38 +01:00
# include <emmintrin.h>
2017-02-08 18:07:34 +01:00
# endif
2017-02-12 11:20:55 +01:00
static const char * vscode =
2017-02-08 18:07:34 +01:00
" struct VS_IN { \n "
" float4 ObjPos : POSITION; \n "
" float2 Uv : TEXCOORD0; \n "
" }; "
" struct VS_OUT { \n "
" float2 Uv : TEXCOORD0; \n "
2017-02-10 00:01:56 +01:00
" float4 ProjPos : SV_Position; \n "
2017-02-08 18:07:34 +01:00
" }; \n "
" VS_OUT main(VS_IN In) { \n "
" VS_OUT Out; \n "
" Out.ProjPos = In.ObjPos; \n "
" Out.Uv = In.Uv; \n "
" return Out; \n "
" } \n " ;
2017-02-12 11:20:55 +01:00
static const char * pscode =
2017-02-08 18:07:34 +01:00
" SamplerState samp : register(s0); \n "
" Texture2D<float4> tex : register(t0); \n "
" struct PS_IN { \n "
" float2 Uv : TEXCOORD0; \n "
" }; \n "
" float4 main( PS_IN In ) : SV_Target { \n "
" float4 c = tex.Sample(samp, In.Uv); \n "
" return c; \n "
" } \n " ;
2017-02-12 13:55:49 +01:00
const D3D11_INPUT_ELEMENT_DESC FramebufferManagerD3D11 : : g_QuadVertexElements [ 2 ] = {
2017-02-08 18:07:34 +01:00
{ " POSITION " , 0 , DXGI_FORMAT_R32G32B32_FLOAT , 0 , 0 , } ,
{ " TEXCOORD " , 0 , DXGI_FORMAT_R32G32_FLOAT , 0 , 12 , } ,
} ;
2017-02-23 11:26:16 +01:00
// The current simple shader translator outputs everything as semantic texcoords, so let's just play along
// for simplicity.
const D3D11_INPUT_ELEMENT_DESC FramebufferManagerD3D11 : : g_PostVertexElements [ 2 ] = {
{ " TEXCOORD " , 0 , DXGI_FORMAT_R32G32B32_FLOAT , 0 , 0 , } ,
{ " TEXCOORD " , 1 , DXGI_FORMAT_R32G32_FLOAT , 0 , 12 , } ,
} ;
2017-02-08 18:07:34 +01:00
FramebufferManagerD3D11 : : FramebufferManagerD3D11 ( Draw : : DrawContext * draw )
2017-02-12 13:55:49 +01:00
: FramebufferManagerCommon ( draw ) {
2017-02-08 18:07:34 +01:00
device_ = ( ID3D11Device * ) draw - > GetNativeObject ( Draw : : NativeObject : : DEVICE ) ;
context_ = ( ID3D11DeviceContext * ) draw - > GetNativeObject ( Draw : : NativeObject : : CONTEXT ) ;
2017-03-05 12:26:46 +01:00
featureLevel_ = ( D3D_FEATURE_LEVEL ) draw - > GetNativeObject ( Draw : : NativeObject : : FEATURE_LEVEL ) ;
2017-02-08 18:07:34 +01:00
std : : vector < uint8_t > bytecode ;
std : : string errorMsg ;
2017-03-05 12:26:46 +01:00
quadVertexShader_ = CreateVertexShaderD3D11 ( device_ , vscode , strlen ( vscode ) , & bytecode , featureLevel_ ) ;
quadPixelShader_ = CreatePixelShaderD3D11 ( device_ , pscode , strlen ( pscode ) , featureLevel_ ) ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateInputLayout ( g_QuadVertexElements , ARRAY_SIZE ( g_QuadVertexElements ) , bytecode . data ( ) , bytecode . size ( ) , & quadInputLayout_ ) ) ;
2017-02-12 11:20:55 +01:00
// STRIP geometry
static const float fsCoord [ 20 ] = {
- 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f ,
1.0f , - 1.0f , 0.0f , 1.0f , 0.0f ,
- 1.0f , 1.0f , 0.0f , 0.0f , 1.0f ,
1.0f , 1.0f , 0.0f , 1.0f , 1.0f ,
2017-02-08 18:07:34 +01:00
} ;
D3D11_BUFFER_DESC vb { } ;
vb . ByteWidth = 20 * 4 ;
vb . Usage = D3D11_USAGE_IMMUTABLE ;
vb . CPUAccessFlags = 0 ;
2017-02-12 11:20:55 +01:00
vb . BindFlags = D3D11_BIND_VERTEX_BUFFER ;
D3D11_SUBRESOURCE_DATA data { fsCoord } ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateBuffer ( & vb , & data , & fsQuadBuffer_ ) ) ;
2017-02-12 11:20:55 +01:00
vb . Usage = D3D11_USAGE_DYNAMIC ;
vb . CPUAccessFlags = D3D11_CPU_ACCESS_WRITE ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateBuffer ( & vb , nullptr , & quadBuffer_ ) ) ;
2017-02-16 16:37:34 +01:00
vb . ByteWidth = ROUND_UP ( sizeof ( PostShaderUniforms ) , 16 ) ;
vb . Usage = D3D11_USAGE_DYNAMIC ;
2017-02-23 14:51:05 +01:00
vb . BindFlags = D3D11_BIND_CONSTANT_BUFFER ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateBuffer ( & vb , nullptr , & postConstants_ ) ) ;
2017-02-16 16:37:34 +01:00
ShaderTranslationInit ( ) ;
CompilePostShader ( ) ;
2017-02-14 12:42:35 +01:00
D3D11_TEXTURE2D_DESC packDesc { } ;
packDesc . CPUAccessFlags = D3D11_CPU_ACCESS_READ ;
packDesc . BindFlags = 0 ;
packDesc . Width = 512 ; // 512x512 is the maximum size of a framebuffer on the PSP.
packDesc . Height = 512 ;
packDesc . ArraySize = 1 ;
packDesc . MipLevels = 1 ;
packDesc . Usage = D3D11_USAGE_STAGING ;
packDesc . SampleDesc . Count = 1 ;
packDesc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateTexture2D ( & packDesc , nullptr , & packTexture_ ) ) ;
2017-02-08 18:07:34 +01:00
}
FramebufferManagerD3D11 : : ~ FramebufferManagerD3D11 ( ) {
2017-02-18 00:27:32 +01:00
packTexture_ - > Release ( ) ;
2017-02-16 16:37:34 +01:00
ShaderTranslationShutdown ( ) ;
2017-02-09 13:27:45 +01:00
// Drawing cleanup
2017-02-12 13:55:49 +01:00
if ( quadVertexShader_ )
2017-02-12 11:20:55 +01:00
quadVertexShader_ - > Release ( ) ;
2017-02-12 13:55:49 +01:00
if ( quadPixelShader_ )
2017-02-12 11:20:55 +01:00
quadPixelShader_ - > Release ( ) ;
2017-02-12 13:55:49 +01:00
quadInputLayout_ - > Release ( ) ;
2017-02-12 11:20:55 +01:00
quadBuffer_ - > Release ( ) ;
fsQuadBuffer_ - > Release ( ) ;
2017-02-23 14:51:05 +01:00
postConstants_ - > Release ( ) ;
2017-02-09 13:27:45 +01:00
2017-02-12 13:55:49 +01:00
if ( drawPixelsTex_ )
drawPixelsTex_ - > Release ( ) ;
if ( drawPixelsTexView_ )
drawPixelsTexView_ - > Release ( ) ;
2017-02-23 11:26:16 +01:00
if ( postVertexShader_ ) {
postVertexShader_ - > Release ( ) ;
}
if ( postPixelShader_ ) {
postPixelShader_ - > Release ( ) ;
}
if ( postInputLayout_ ) {
postInputLayout_ - > Release ( ) ;
}
2017-02-09 13:27:45 +01:00
// FBO cleanup
2017-02-08 18:07:34 +01:00
for ( auto it = tempFBOs_ . begin ( ) , end = tempFBOs_ . end ( ) ; it ! = end ; + + it ) {
2017-02-17 19:22:41 +01:00
it - > second . fbo - > Release ( ) ;
2017-02-08 18:07:34 +01:00
}
delete [ ] convBuf ;
2017-02-09 13:27:45 +01:00
// Stencil cleanup
for ( int i = 0 ; i < 256 ; i + + ) {
if ( stencilMaskStates_ [ i ] )
stencilMaskStates_ [ i ] - > Release ( ) ;
}
2017-02-12 13:55:49 +01:00
if ( stencilUploadPS_ )
2017-02-08 18:07:34 +01:00
stencilUploadPS_ - > Release ( ) ;
2017-02-12 13:55:49 +01:00
if ( stencilUploadVS_ )
2017-02-08 18:07:34 +01:00
stencilUploadVS_ - > Release ( ) ;
2017-02-12 13:55:49 +01:00
if ( stencilUploadInputLayout_ )
stencilUploadInputLayout_ - > Release ( ) ;
2017-02-13 17:29:36 +01:00
if ( stencilValueBuffer_ )
stencilValueBuffer_ - > Release ( ) ;
2017-02-08 18:07:34 +01:00
}
void FramebufferManagerD3D11 : : SetTextureCache ( TextureCacheD3D11 * tc ) {
textureCacheD3D11_ = tc ;
textureCache_ = tc ;
}
2017-02-15 18:32:44 +01:00
void FramebufferManagerD3D11 : : SetShaderManager ( ShaderManagerD3D11 * sm ) {
shaderManagerD3D11_ = sm ;
shaderManager_ = sm ;
}
2017-02-12 11:20:55 +01:00
void FramebufferManagerD3D11 : : ClearBuffer ( bool keepState ) {
2017-02-15 11:06:59 +01:00
draw_ - > Clear ( Draw : : FBChannel : : FB_COLOR_BIT | Draw : : FBChannel : : FB_DEPTH_BIT | Draw : : FBChannel : : FB_STENCIL_BIT , 0 , ToScaledDepth ( 0 ) , 0 ) ;
2017-02-12 11:20:55 +01:00
}
void FramebufferManagerD3D11 : : DisableState ( ) {
context_ - > OMSetBlendState ( stockD3D11 . blendStateDisabledWithColorMask [ 0xF ] , nullptr , 0xFFFFFFFF ) ;
context_ - > RSSetState ( stockD3D11 . rasterStateNoCull ) ;
context_ - > OMSetDepthStencilState ( stockD3D11 . depthStencilDisabled , 0xFF ) ;
}
2017-02-16 16:37:34 +01:00
void FramebufferManagerD3D11 : : CompilePostShader ( ) {
SetNumExtraFBOs ( 0 ) ;
std : : string vsSource ;
std : : string psSource ;
2017-02-23 11:26:16 +01:00
if ( postVertexShader_ ) {
postVertexShader_ - > Release ( ) ;
postVertexShader_ = nullptr ;
}
if ( postPixelShader_ ) {
postPixelShader_ - > Release ( ) ;
postPixelShader_ = nullptr ;
}
if ( postInputLayout_ ) {
postInputLayout_ - > Release ( ) ;
postInputLayout_ = nullptr ;
}
2017-03-11 12:25:43 +01:00
const ShaderInfo * shaderInfo = nullptr ;
2017-02-16 16:37:34 +01:00
if ( g_Config . sPostShaderName = = " Off " ) {
2017-02-23 12:41:22 +01:00
usePostShader_ = false ;
2017-02-16 16:37:34 +01:00
return ;
}
2017-02-23 12:41:22 +01:00
usePostShader_ = false ;
2017-03-11 12:25:43 +01:00
ReloadAllPostShaderInfo ( ) ;
2017-02-16 16:37:34 +01:00
shaderInfo = GetPostShaderInfo ( g_Config . sPostShaderName ) ;
if ( shaderInfo ) {
postShaderAtOutputResolution_ = shaderInfo - > outputResolution ;
size_t sz ;
char * vs = ( char * ) VFSReadFile ( shaderInfo - > vertexShaderFile . c_str ( ) , & sz ) ;
if ( ! vs )
return ;
char * ps = ( char * ) VFSReadFile ( shaderInfo - > fragmentShaderFile . c_str ( ) , & sz ) ;
if ( ! ps ) {
free ( vs ) ;
return ;
}
std : : string vsSourceGLSL = vs ;
std : : string psSourceGLSL = ps ;
free ( vs ) ;
free ( ps ) ;
TranslatedShaderMetadata metaVS , metaFS ;
std : : string errorVS , errorFS ;
if ( ! TranslateShader ( & vsSource , HLSL_D3D11 , & metaVS , vsSourceGLSL , GLSL_140 , Draw : : ShaderStage : : VERTEX , & errorVS ) )
return ;
if ( ! TranslateShader ( & psSource , HLSL_D3D11 , & metaFS , psSourceGLSL , GLSL_140 , Draw : : ShaderStage : : FRAGMENT , & errorFS ) )
return ;
} else {
return ;
}
2017-02-23 12:41:22 +01:00
I18NCategory * gr = GetI18NCategory ( " Graphics " ) ;
2017-02-16 16:37:34 +01:00
2017-02-23 11:26:16 +01:00
UINT flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY ;
2017-02-16 16:37:34 +01:00
std : : vector < uint8_t > byteCode ;
2017-03-05 12:26:46 +01:00
postVertexShader_ = CreateVertexShaderD3D11 ( device_ , vsSource . data ( ) , vsSource . size ( ) , & byteCode , featureLevel_ , flags ) ;
2017-02-16 16:37:34 +01:00
if ( ! postVertexShader_ ) {
return ;
}
2017-03-05 12:26:46 +01:00
postPixelShader_ = CreatePixelShaderD3D11 ( device_ , psSource . data ( ) , psSource . size ( ) , featureLevel_ , flags ) ;
2017-02-16 16:37:34 +01:00
if ( ! postPixelShader_ ) {
postVertexShader_ - > Release ( ) ;
return ;
}
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateInputLayout ( g_PostVertexElements , 2 , byteCode . data ( ) , byteCode . size ( ) , & postInputLayout_ ) ) ;
2017-02-16 16:37:34 +01:00
usePostShader_ = true ;
}
2017-03-22 20:56:26 -07:00
void FramebufferManagerD3D11 : : MakePixelTexture ( const u8 * srcPixels , GEBufferFormat srcPixelFormat , int srcStride , int width , int height , float & u1 , float & v1 ) {
2017-02-08 18:07:34 +01:00
u8 * convBuf = NULL ;
// TODO: Check / use D3DCAPS2_DYNAMICTEXTURES?
if ( drawPixelsTex_ & & ( drawPixelsTexW_ ! = width | | drawPixelsTexH_ ! = height ) ) {
drawPixelsTex_ - > Release ( ) ;
drawPixelsTex_ = nullptr ;
2017-02-20 21:35:34 +01:00
drawPixelsTexView_ - > Release ( ) ;
drawPixelsTexView_ = nullptr ;
2017-02-08 18:07:34 +01:00
}
if ( ! drawPixelsTex_ ) {
int usage = 0 ;
D3D11_TEXTURE2D_DESC desc { } ;
desc . Usage = D3D11_USAGE_DYNAMIC ;
desc . CPUAccessFlags = D3D11_CPU_ACCESS_WRITE ;
desc . Width = width ;
desc . Height = height ;
2017-02-09 13:57:24 +01:00
desc . MipLevels = 1 ;
desc . ArraySize = 1 ;
desc . SampleDesc . Count = 1 ;
2017-02-14 01:31:45 +01:00
desc . Format = DXGI_FORMAT_B8G8R8A8_UNORM ;
2017-02-09 13:57:24 +01:00
desc . BindFlags = D3D11_BIND_SHADER_RESOURCE ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateTexture2D ( & desc , nullptr , & drawPixelsTex_ ) ) ;
ASSERT_SUCCESS ( device_ - > CreateShaderResourceView ( drawPixelsTex_ , nullptr , & drawPixelsTexView_ ) ) ;
2017-02-08 18:07:34 +01:00
drawPixelsTexW_ = width ;
drawPixelsTexH_ = height ;
}
if ( ! drawPixelsTex_ ) {
return ;
}
D3D11_MAPPED_SUBRESOURCE map ;
context_ - > Map ( drawPixelsTex_ , 0 , D3D11_MAP_WRITE_DISCARD , 0 , & map ) ;
convBuf = ( u8 * ) map . pData ;
if ( srcPixelFormat ! = GE_FORMAT_8888 | | srcStride ! = 512 ) {
for ( int y = 0 ; y < height ; y + + ) {
switch ( srcPixelFormat ) {
case GE_FORMAT_565 :
{
const u16_le * src = ( const u16_le * ) srcPixels + srcStride * y ;
u32 * dst = ( u32 * ) ( convBuf + map . RowPitch * y ) ;
ConvertRGB565ToBGRA8888 ( dst , src , width ) ;
}
break ;
// faster
case GE_FORMAT_5551 :
{
const u16_le * src = ( const u16_le * ) srcPixels + srcStride * y ;
u32 * dst = ( u32 * ) ( convBuf + map . RowPitch * y ) ;
ConvertRGBA5551ToBGRA8888 ( dst , src , width ) ;
}
break ;
case GE_FORMAT_4444 :
{
const u16_le * src = ( const u16_le * ) srcPixels + srcStride * y ;
u8 * dst = ( u8 * ) ( convBuf + map . RowPitch * y ) ;
ConvertRGBA4444ToBGRA8888 ( ( u32 * ) dst , src , width ) ;
}
break ;
case GE_FORMAT_8888 :
{
const u32_le * src = ( const u32_le * ) srcPixels + srcStride * y ;
u32 * dst = ( u32 * ) ( convBuf + map . RowPitch * y ) ;
2017-02-14 01:31:45 +01:00
ConvertRGBA8888ToBGRA8888 ( dst , src , width ) ;
2017-02-08 18:07:34 +01:00
}
break ;
}
}
} else {
for ( int y = 0 ; y < height ; y + + ) {
const u32_le * src = ( const u32_le * ) srcPixels + srcStride * y ;
u32 * dst = ( u32 * ) ( convBuf + map . RowPitch * y ) ;
2017-02-14 01:31:45 +01:00
ConvertRGBA8888ToBGRA8888 ( dst , src , width ) ;
2017-02-08 18:07:34 +01:00
}
}
context_ - > Unmap ( drawPixelsTex_ , 0 ) ;
2017-02-15 16:01:59 +01:00
context_ - > PSSetShaderResources ( 0 , 1 , & drawPixelsTexView_ ) ;
2017-02-08 18:07:34 +01:00
// D3DXSaveTextureToFile("game:\\cc.png", D3DXIFF_PNG, drawPixelsTex_, NULL);
}
void FramebufferManagerD3D11 : : DrawActiveTexture ( float x , float y , float w , float h , float destW , float destH , float u0 , float v0 , float u1 , float v1 , int uvRotation , bool linearFilter ) {
2017-03-07 13:00:59 +01:00
struct Coord {
Vec3 pos ; float u , v ;
} ;
Coord coord [ 4 ] = {
{ { x , y , 0 } , u0 , v0 } ,
{ { x + w , y , 0 } , u1 , v0 } ,
{ { x + w , y + h , 0 } , u1 , v1 } ,
{ { x , y + h , 0 } , u0 , v1 } ,
2017-02-08 18:07:34 +01:00
} ;
static const short indices [ 4 ] = { 0 , 1 , 3 , 2 } ;
if ( uvRotation ! = ROTATION_LOCKED_HORIZONTAL ) {
float temp [ 8 ] ;
int rotation = 0 ;
switch ( uvRotation ) {
case ROTATION_LOCKED_HORIZONTAL180 : rotation = 2 ; break ;
case ROTATION_LOCKED_VERTICAL : rotation = 1 ; break ;
case ROTATION_LOCKED_VERTICAL180 : rotation = 3 ; break ;
}
for ( int i = 0 ; i < 4 ; i + + ) {
2017-03-07 13:00:59 +01:00
temp [ i * 2 ] = coord [ ( ( i + rotation ) & 3 ) ] . u ;
temp [ i * 2 + 1 ] = coord [ ( ( i + rotation ) & 3 ) ] . v ;
2017-02-08 18:07:34 +01:00
}
for ( int i = 0 ; i < 4 ; i + + ) {
2017-03-07 13:00:59 +01:00
coord [ i ] . u = temp [ i * 2 ] ;
coord [ i ] . v = temp [ i * 2 + 1 ] ;
2017-02-08 18:07:34 +01:00
}
}
float invDestW = 1.0f / ( destW * 0.5f ) ;
float invDestH = 1.0f / ( destH * 0.5f ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
2017-03-19 14:57:48 +01:00
coord [ i ] . pos . x = coord [ i ] . pos . x * invDestW - 1.0f ;
coord [ i ] . pos . y = - ( coord [ i ] . pos . y * invDestH - 1.0f ) ;
2017-03-07 13:00:59 +01:00
}
if ( g_display_rotation ! = DisplayRotation : : ROTATE_0 ) {
for ( int i = 0 ; i < 4 ; i + + ) {
// backwards notation, should fix that...
coord [ i ] . pos = coord [ i ] . pos * g_display_rot_matrix ;
}
2017-02-08 18:07:34 +01:00
}
2017-02-12 11:20:55 +01:00
// The above code is for FAN geometry but we can only do STRIP. So rearrange it a little.
D3D11_MAPPED_SUBRESOURCE map ;
context_ - > Map ( quadBuffer_ , 0 , D3D11_MAP_WRITE_DISCARD , 0 , & map ) ;
float * dest = ( float * ) map . pData ;
2017-03-07 13:00:59 +01:00
memcpy ( dest , coord , sizeof ( Coord ) ) ;
memcpy ( dest + 5 , coord + 1 , sizeof ( Coord ) ) ;
memcpy ( dest + 10 , coord + 3 , sizeof ( Coord ) ) ;
memcpy ( dest + 15 , coord + 2 , sizeof ( Coord ) ) ;
2017-02-12 11:20:55 +01:00
context_ - > Unmap ( quadBuffer_ , 0 ) ;
2017-02-08 18:07:34 +01:00
context_ - > RSSetState ( stockD3D11 . rasterStateNoCull ) ;
context_ - > OMSetBlendState ( stockD3D11 . blendStateDisabledWithColorMask [ 0xF ] , nullptr , 0xFFFFFFFF ) ;
2017-02-12 11:20:55 +01:00
context_ - > OMSetDepthStencilState ( stockD3D11 . depthStencilDisabled , 0 ) ;
2017-02-08 18:07:34 +01:00
context_ - > IASetPrimitiveTopology ( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ) ;
2017-02-12 11:20:55 +01:00
context_ - > PSSetSamplers ( 0 , 1 , linearFilter ? & stockD3D11 . samplerLinear2DClamp : & stockD3D11 . samplerPoint2DClamp ) ;
UINT stride = 20 ;
UINT offset = 0 ;
context_ - > IASetVertexBuffers ( 0 , 1 , & quadBuffer_ , & stride , & offset ) ;
context_ - > Draw ( 4 , 0 ) ;
2017-02-15 16:01:59 +01:00
}
void FramebufferManagerD3D11 : : Bind2DShader ( ) {
context_ - > IASetInputLayout ( quadInputLayout_ ) ;
context_ - > PSSetShader ( quadPixelShader_ , 0 , 0 ) ;
context_ - > VSSetShader ( quadVertexShader_ , 0 , 0 ) ;
}
void FramebufferManagerD3D11 : : BindPostShader ( const PostShaderUniforms & uniforms ) {
2017-02-16 16:37:34 +01:00
if ( ! postPixelShader_ ) {
if ( usePostShader_ ) {
CompilePostShader ( ) ;
}
if ( ! usePostShader_ ) {
context_ - > IASetInputLayout ( quadInputLayout_ ) ;
context_ - > PSSetShader ( quadPixelShader_ , 0 , 0 ) ;
context_ - > VSSetShader ( quadVertexShader_ , 0 , 0 ) ;
return ;
}
}
context_ - > IASetInputLayout ( postInputLayout_ ) ;
context_ - > PSSetShader ( postPixelShader_ , 0 , 0 ) ;
context_ - > VSSetShader ( postVertexShader_ , 0 , 0 ) ;
2017-02-23 14:51:05 +01:00
D3D11_MAPPED_SUBRESOURCE map ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( context_ - > Map ( postConstants_ , 0 , D3D11_MAP_WRITE_DISCARD , 0 , & map ) ) ;
2017-02-23 14:51:05 +01:00
memcpy ( map . pData , & uniforms , sizeof ( uniforms ) ) ;
context_ - > Unmap ( postConstants_ , 0 ) ;
context_ - > VSSetConstantBuffers ( 0 , 1 , & postConstants_ ) ; // Probably not necessary
context_ - > PSSetConstantBuffers ( 0 , 1 , & postConstants_ ) ;
2017-02-08 18:07:34 +01:00
}
void FramebufferManagerD3D11 : : RebindFramebuffer ( ) {
if ( currentRenderVfb_ & & currentRenderVfb_ - > fbo ) {
draw_ - > BindFramebufferAsRenderTarget ( currentRenderVfb_ - > fbo ) ;
} else {
2017-05-16 13:53:57 +02:00
draw_ - > BindFramebufferAsRenderTarget ( nullptr ) ;
2017-02-08 18:07:34 +01:00
}
}
void FramebufferManagerD3D11 : : ReformatFramebufferFrom ( VirtualFramebuffer * vfb , GEBufferFormat old ) {
if ( ! useBufferedRendering_ | | ! vfb - > fbo ) {
return ;
}
draw_ - > BindFramebufferAsRenderTarget ( vfb - > fbo ) ;
// Technically, we should at this point re-interpret the bytes of the old format to the new.
// That might get tricky, and could cause unnecessary slowness in some games.
// For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts.
// (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.)
//
// The best way to do this may ultimately be to create a new FBO (combine with any resize?)
// and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex
// to exactly reproduce in 4444 and 8888 formats.
if ( old = = GE_FORMAT_565 ) {
context_ - > OMSetDepthStencilState ( stockD3D11 . depthDisabledStencilWrite , 0xFF ) ;
context_ - > OMSetBlendState ( stockD3D11 . blendStateDisabledWithColorMask [ 0 ] , nullptr , 0xFFFFFFFF ) ;
context_ - > RSSetState ( stockD3D11 . rasterStateNoCull ) ;
2017-02-12 13:55:49 +01:00
context_ - > IASetInputLayout ( quadInputLayout_ ) ;
2017-02-12 11:20:55 +01:00
context_ - > PSSetShader ( quadPixelShader_ , nullptr , 0 ) ;
context_ - > VSSetShader ( quadVertexShader_ , nullptr , 0 ) ;
2017-02-12 13:55:49 +01:00
context_ - > IASetVertexBuffers ( 0 , 1 , & fsQuadBuffer_ , & quadStride_ , & quadOffset_ ) ;
2017-02-15 18:32:44 +01:00
shaderManagerD3D11_ - > DirtyLastShader ( ) ;
2017-02-08 18:07:34 +01:00
D3D11_VIEWPORT vp { 0.0f , 0.0f , ( float ) vfb - > renderWidth , ( float ) vfb - > renderHeight , 0.0f , 1.0f } ;
context_ - > RSSetViewports ( 1 , & vp ) ;
context_ - > IASetPrimitiveTopology ( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ) ;
2017-02-17 17:00:35 +01:00
context_ - > Draw ( 4 , 0 ) ;
2017-02-08 18:07:34 +01:00
}
RebindFramebuffer ( ) ;
}
static void CopyPixelDepthOnly ( u32 * dstp , const u32 * srcp , size_t c ) {
size_t x = 0 ;
# ifdef _M_SSE
size_t sseSize = ( c / 4 ) * 4 ;
const __m128i srcMask = _mm_set1_epi32 ( 0x00FFFFFF ) ;
const __m128i dstMask = _mm_set1_epi32 ( 0xFF000000 ) ;
__m128i * dst = ( __m128i * ) dstp ;
const __m128i * src = ( const __m128i * ) srcp ;
for ( ; x < sseSize ; x + = 4 ) {
const __m128i bits24 = _mm_and_si128 ( _mm_load_si128 ( src ) , srcMask ) ;
const __m128i bits8 = _mm_and_si128 ( _mm_load_si128 ( dst ) , dstMask ) ;
_mm_store_si128 ( dst , _mm_or_si128 ( bits24 , bits8 ) ) ;
dst + + ;
src + + ;
}
# endif
// Copy the remaining pixels that didn't fit in SSE.
for ( ; x < c ; + + x ) {
memcpy ( dstp + x , srcp + x , 3 ) ;
}
}
void FramebufferManagerD3D11 : : BlitFramebufferDepth ( VirtualFramebuffer * src , VirtualFramebuffer * dst ) {
if ( g_Config . bDisableSlowFramebufEffects ) {
return ;
}
bool matchingDepthBuffer = src - > z_address = = dst - > z_address & & src - > z_stride ! = 0 & & dst - > z_stride ! = 0 ;
bool matchingSize = src - > width = = dst - > width & & src - > height = = dst - > height ;
2017-02-17 12:51:37 +01:00
bool matchingRenderSize = src - > renderWidth = = dst - > renderWidth & & src - > renderHeight = = dst - > renderHeight ;
if ( matchingDepthBuffer & & matchingSize & & matchingRenderSize ) {
2017-02-13 01:22:55 +01:00
draw_ - > CopyFramebufferImage ( src - > fbo , 0 , 0 , 0 , 0 , dst - > fbo , 0 , 0 , 0 , 0 , src - > renderWidth , src - > renderHeight , 1 , Draw : : FB_DEPTH_BIT ) ;
2017-02-08 18:07:34 +01:00
RebindFramebuffer ( ) ;
2017-02-12 11:20:55 +01:00
}
2017-02-08 18:07:34 +01:00
}
2017-02-17 14:30:42 +01:00
void FramebufferManagerD3D11 : : BindFramebufferAsColorTexture ( int stage , VirtualFramebuffer * framebuffer , int flags ) {
2017-02-08 18:07:34 +01:00
if ( ! framebuffer - > fbo | | ! useBufferedRendering_ ) {
2017-02-10 11:25:24 +01:00
ID3D11ShaderResourceView * view = nullptr ;
context_ - > PSSetShaderResources ( stage , 1 , & view ) ;
2017-02-08 18:07:34 +01:00
gstate_c . skipDrawReason | = SKIPDRAW_BAD_FB_TEXTURE ;
return ;
}
// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
// Let's just not bother with the copy in that case.
bool skipCopy = ( flags & BINDFBCOLOR_MAY_COPY ) = = 0 ;
if ( GPUStepping : : IsStepping ( ) | | g_Config . bDisableSlowFramebufEffects ) {
skipCopy = true ;
}
// Currently rendering to this framebuffer. Need to make a copy.
2017-02-17 14:30:42 +01:00
if ( ! skipCopy & & framebuffer = = currentRenderVfb_ ) {
2017-02-08 18:07:34 +01:00
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
Draw : : Framebuffer * renderCopy = GetTempFBO ( framebuffer - > renderWidth , framebuffer - > renderHeight , ( Draw : : FBColorDepth ) framebuffer - > colorDepth ) ;
if ( renderCopy ) {
VirtualFramebuffer copyInfo = * framebuffer ;
copyInfo . fbo = renderCopy ;
2017-04-06 18:49:48 -07:00
CopyFramebufferForColorTexture ( & copyInfo , framebuffer , flags ) ;
2017-02-08 18:07:34 +01:00
RebindFramebuffer ( ) ;
draw_ - > BindFramebufferAsTexture ( renderCopy , stage , Draw : : FB_COLOR_BIT , 0 ) ;
} else {
draw_ - > BindFramebufferAsTexture ( framebuffer - > fbo , stage , Draw : : FB_COLOR_BIT , 0 ) ;
}
2017-02-17 14:30:42 +01:00
} else if ( framebuffer ! = currentRenderVfb_ ) {
2017-02-08 18:07:34 +01:00
draw_ - > BindFramebufferAsTexture ( framebuffer - > fbo , stage , Draw : : FB_COLOR_BIT , 0 ) ;
2017-02-17 14:30:42 +01:00
} else {
2017-03-18 13:52:30 -07:00
ERROR_LOG_REPORT_ONCE ( d3d11SelfTexture , G3D , " Attempting to texture to target " ) ;
2017-02-17 14:30:42 +01:00
// Badness on D3D11 to bind the currently rendered-to framebuffer as a texture.
ID3D11ShaderResourceView * view = nullptr ;
context_ - > PSSetShaderResources ( stage , 1 , & view ) ;
gstate_c . skipDrawReason | = SKIPDRAW_BAD_FB_TEXTURE ;
return ;
2017-02-08 18:07:34 +01:00
}
}
void FramebufferManagerD3D11 : : ReadFramebufferToMemory ( VirtualFramebuffer * vfb , bool sync , int x , int y , int w , int h ) {
if ( vfb ) {
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
OptimizeDownloadRange ( vfb , x , y , w , h ) ;
2017-03-19 17:37:28 +01:00
if ( vfb - > renderWidth = = vfb - > width & & vfb - > renderHeight = = vfb - > height ) {
// No need to blit
PackFramebufferD3D11_ ( vfb , x , y , w , h ) ;
}
else {
VirtualFramebuffer * nvfb = FindDownloadTempBuffer ( vfb ) ;
BlitFramebuffer ( nvfb , x , y , vfb , x , y , w , h , 0 ) ;
PackFramebufferD3D11_ ( nvfb , x , y , w , h ) ;
}
2017-02-08 18:07:34 +01:00
textureCacheD3D11_ - > ForgetLastTexture ( ) ;
RebindFramebuffer ( ) ;
}
}
void FramebufferManagerD3D11 : : DownloadFramebufferForClut ( u32 fb_address , u32 loadBytes ) {
VirtualFramebuffer * vfb = GetVFBAt ( fb_address ) ;
if ( vfb & & vfb - > fb_stride ! = 0 ) {
const u32 bpp = vfb - > drawnFormat = = GE_FORMAT_8888 ? 4 : 2 ;
int x = 0 ;
int y = 0 ;
int pixels = loadBytes / bpp ;
// The height will be 1 for each stride or part thereof.
int w = std : : min ( pixels % vfb - > fb_stride , ( int ) vfb - > width ) ;
int h = std : : min ( ( pixels + vfb - > fb_stride - 1 ) / vfb - > fb_stride , ( int ) vfb - > height ) ;
// We might still have a pending draw to the fb in question, flush if so.
FlushBeforeCopy ( ) ;
// No need to download if we already have it.
if ( ! vfb - > memoryUpdated & & vfb - > clutUpdatedBytes < loadBytes ) {
// We intentionally don't call OptimizeDownloadRange() here - we don't want to over download.
// CLUT framebuffers are often incorrectly estimated in size.
if ( x = = 0 & & y = = 0 & & w = = vfb - > width & & h = = vfb - > height ) {
vfb - > memoryUpdated = true ;
}
vfb - > clutUpdatedBytes = loadBytes ;
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer * nvfb = FindDownloadTempBuffer ( vfb ) ;
BlitFramebuffer ( nvfb , x , y , vfb , x , y , w , h , 0 ) ;
PackFramebufferD3D11_ ( nvfb , x , y , w , h ) ;
textureCacheD3D11_ - > ForgetLastTexture ( ) ;
RebindFramebuffer ( ) ;
}
}
}
bool FramebufferManagerD3D11 : : CreateDownloadTempBuffer ( VirtualFramebuffer * nvfb ) {
nvfb - > colorDepth = Draw : : FBO_8888 ;
nvfb - > fbo = draw_ - > CreateFramebuffer ( { nvfb - > width , nvfb - > height , 1 , 1 , true , ( Draw : : FBColorDepth ) nvfb - > colorDepth } ) ;
if ( ! ( nvfb - > fbo ) ) {
2017-03-13 12:32:21 +01:00
ERROR_LOG ( FRAMEBUF , " Error creating FBO! %i x %i " , nvfb - > renderWidth , nvfb - > renderHeight ) ;
2017-02-08 18:07:34 +01:00
return false ;
}
draw_ - > BindFramebufferAsRenderTarget ( nvfb - > fbo ) ;
ClearBuffer ( ) ;
return true ;
}
void FramebufferManagerD3D11 : : UpdateDownloadTempBuffer ( VirtualFramebuffer * nvfb ) {
// Nothing to do here.
}
2017-02-17 12:51:37 +01:00
void FramebufferManagerD3D11 : : SimpleBlit (
Draw : : Framebuffer * dest , float destX1 , float destY1 , float destX2 , float destY2 ,
Draw : : Framebuffer * src , float srcX1 , float srcY1 , float srcX2 , float srcY2 , bool linearFilter ) {
int destW , destH , srcW , srcH ;
draw_ - > GetFramebufferDimensions ( src , & srcW , & srcH ) ;
draw_ - > GetFramebufferDimensions ( dest , & destW , & destH ) ;
if ( srcW = = destW & & srcH = = destH & & destX2 - destX1 = = srcX2 - srcX1 & & destY2 - destY1 = = srcY2 - srcY1 ) {
// Optimize to a copy
draw_ - > CopyFramebufferImage ( src , 0 , ( int ) srcX1 , ( int ) srcY1 , 0 , dest , 0 , ( int ) destX1 , ( int ) destY1 , 0 , ( int ) ( srcX2 - srcX1 ) , ( int ) ( srcY2 - srcY1 ) , 1 , Draw : : FB_COLOR_BIT ) ;
return ;
}
float dX = 1.0f / ( float ) destW ;
float dY = 1.0f / ( float ) destH ;
float sX = 1.0f / ( float ) srcW ;
float sY = 1.0f / ( float ) srcH ;
struct Vtx {
float x , y , z , u , v ;
} ;
Vtx vtx [ 4 ] = {
2017-02-17 18:43:27 +01:00
{ - 1.0f + 2.0f * dX * destX1 , 1.0f - 2.0f * dY * destY1 , 0.0f , sX * srcX1 , sY * srcY1 } ,
{ - 1.0f + 2.0f * dX * destX2 , 1.0f - 2.0f * dY * destY1 , 0.0f , sX * srcX2 , sY * srcY1 } ,
{ - 1.0f + 2.0f * dX * destX1 , 1.0f - 2.0f * dY * destY2 , 0.0f , sX * srcX1 , sY * srcY2 } ,
{ - 1.0f + 2.0f * dX * destX2 , 1.0f - 2.0f * dY * destY2 , 0.0f , sX * srcX2 , sY * srcY2 } ,
2017-02-17 12:51:37 +01:00
} ;
D3D11_MAPPED_SUBRESOURCE map ;
2017-03-05 13:59:16 +01:00
ASSERT_SUCCESS ( context_ - > Map ( quadBuffer_ , 0 , D3D11_MAP_WRITE_DISCARD , 0 , & map ) ) ;
2017-02-17 12:51:37 +01:00
memcpy ( map . pData , vtx , 4 * sizeof ( Vtx ) ) ;
context_ - > Unmap ( quadBuffer_ , 0 ) ;
2017-03-19 17:53:26 +01:00
// Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily).
draw_ - > BindTexture ( 0 , nullptr ) ;
2017-03-06 16:39:23 +01:00
draw_ - > BindFramebufferAsRenderTarget ( dest ) ;
2017-03-19 17:53:26 +01:00
draw_ - > BindFramebufferAsTexture ( src , 0 , Draw : : FB_COLOR_BIT , 0 ) ;
2017-03-06 16:39:23 +01:00
2017-02-17 12:51:37 +01:00
Bind2DShader ( ) ;
2017-02-17 19:22:41 +01:00
D3D11_VIEWPORT vp { 0.0f , 0.0f , ( float ) destW , ( float ) destH , 0.0f , 1.0f } ;
context_ - > RSSetViewports ( 1 , & vp ) ;
2017-02-17 12:51:37 +01:00
context_ - > RSSetState ( stockD3D11 . rasterStateNoCull ) ;
context_ - > OMSetBlendState ( stockD3D11 . blendStateDisabledWithColorMask [ 0xF ] , nullptr , 0xFFFFFFFF ) ;
context_ - > OMSetDepthStencilState ( stockD3D11 . depthStencilDisabled , 0 ) ;
context_ - > IASetPrimitiveTopology ( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ) ;
context_ - > PSSetSamplers ( 0 , 1 , linearFilter ? & stockD3D11 . samplerLinear2DClamp : & stockD3D11 . samplerPoint2DClamp ) ;
UINT stride = sizeof ( Vtx ) ;
UINT offset = 0 ;
context_ - > IASetVertexBuffers ( 0 , 1 , & quadBuffer_ , & stride , & offset ) ;
context_ - > Draw ( 4 , 0 ) ;
}
2017-02-08 18:07:34 +01:00
void FramebufferManagerD3D11 : : BlitFramebuffer ( VirtualFramebuffer * dst , int dstX , int dstY , VirtualFramebuffer * src , int srcX , int srcY , int w , int h , int bpp ) {
if ( ! dst - > fbo | | ! src - > fbo | | ! useBufferedRendering_ ) {
// This can happen if they recently switched from non-buffered.
2017-05-16 13:53:57 +02:00
draw_ - > BindFramebufferAsRenderTarget ( nullptr ) ;
2017-02-08 18:07:34 +01:00
return ;
}
float srcXFactor = ( float ) src - > renderWidth / ( float ) src - > bufferWidth ;
float srcYFactor = ( float ) src - > renderHeight / ( float ) src - > bufferHeight ;
const int srcBpp = src - > format = = GE_FORMAT_8888 ? 4 : 2 ;
if ( srcBpp ! = bpp & & bpp ! = 0 ) {
srcXFactor = ( srcXFactor * bpp ) / srcBpp ;
}
int srcX1 = srcX * srcXFactor ;
int srcX2 = ( srcX + w ) * srcXFactor ;
int srcY1 = srcY * srcYFactor ;
int srcY2 = ( srcY + h ) * srcYFactor ;
float dstXFactor = ( float ) dst - > renderWidth / ( float ) dst - > bufferWidth ;
float dstYFactor = ( float ) dst - > renderHeight / ( float ) dst - > bufferHeight ;
const int dstBpp = dst - > format = = GE_FORMAT_8888 ? 4 : 2 ;
if ( dstBpp ! = bpp & & bpp ! = 0 ) {
dstXFactor = ( dstXFactor * bpp ) / dstBpp ;
}
int dstX1 = dstX * dstXFactor ;
int dstX2 = ( dstX + w ) * dstXFactor ;
int dstY1 = dstY * dstYFactor ;
int dstY2 = ( dstY + h ) * dstYFactor ;
2017-02-17 18:43:27 +01:00
// Direct3D doesn't support rect -> self.
2017-02-08 18:07:34 +01:00
Draw : : Framebuffer * srcFBO = src - > fbo ;
if ( src = = dst ) {
Draw : : Framebuffer * tempFBO = GetTempFBO ( src - > renderWidth , src - > renderHeight , ( Draw : : FBColorDepth ) src - > colorDepth ) ;
2017-02-17 12:51:37 +01:00
SimpleBlit ( tempFBO , dstX1 , dstY1 , dstX2 , dstY2 , src - > fbo , srcX1 , srcY1 , srcX2 , srcY2 , false ) ;
srcFBO = tempFBO ;
2017-02-08 18:07:34 +01:00
}
2017-02-17 12:51:37 +01:00
SimpleBlit (
2017-02-08 18:07:34 +01:00
dst - > fbo , dstX1 , dstY1 , dstX2 , dstY2 ,
2017-02-17 12:51:37 +01:00
srcFBO , srcX1 , srcY1 , srcX2 , srcY2 ,
false ) ;
2017-02-08 18:07:34 +01:00
}
// TODO: SSE/NEON
// Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :)
void ConvertFromRGBA8888 ( u8 * dst , u8 * src , u32 dstStride , u32 srcStride , u32 width , u32 height , GEBufferFormat format ) {
// Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP.
const u32 * src32 = ( const u32 * ) src ;
if ( format = = GE_FORMAT_8888 ) {
u32 * dst32 = ( u32 * ) dst ;
if ( src = = dst ) {
return ;
} else {
for ( u32 y = 0 ; y < height ; + + y ) {
2017-02-14 12:42:35 +01:00
memcpy ( dst32 , src32 , width * 4 ) ;
2017-02-08 18:07:34 +01:00
src32 + = srcStride ;
dst32 + = dstStride ;
}
}
} else {
// But here it shouldn't matter if they do intersect
u16 * dst16 = ( u16 * ) dst ;
switch ( format ) {
case GE_FORMAT_565 : // BGR 565
for ( u32 y = 0 ; y < height ; + + y ) {
2017-02-14 12:42:35 +01:00
ConvertRGBA8888ToRGB565 ( dst16 , src32 , width ) ;
2017-02-08 18:07:34 +01:00
src32 + = srcStride ;
dst16 + = dstStride ;
}
break ;
case GE_FORMAT_5551 : // ABGR 1555
for ( u32 y = 0 ; y < height ; + + y ) {
2017-02-14 12:42:35 +01:00
ConvertRGBA8888ToRGBA5551 ( dst16 , src32 , width ) ;
2017-02-08 18:07:34 +01:00
src32 + = srcStride ;
dst16 + = dstStride ;
}
break ;
case GE_FORMAT_4444 : // ABGR 4444
for ( u32 y = 0 ; y < height ; + + y ) {
2017-02-14 12:42:35 +01:00
ConvertRGBA8888ToRGBA4444 ( dst16 , src32 , width ) ;
2017-02-08 18:07:34 +01:00
src32 + = srcStride ;
dst16 + = dstStride ;
}
break ;
case GE_FORMAT_8888 :
case GE_FORMAT_INVALID :
// Not possible.
break ;
}
}
}
2017-02-14 12:42:35 +01:00
// This function takes an already correctly-sized framebuffer and packs it into RAM.
// Does not need to account for scaling.
// Color conversion is currently done on CPU but should be done on GPU.
2017-02-08 18:07:34 +01:00
void FramebufferManagerD3D11 : : PackFramebufferD3D11_ ( VirtualFramebuffer * vfb , int x , int y , int w , int h ) {
if ( ! vfb - > fbo ) {
ERROR_LOG_REPORT_ONCE ( vfbfbozero , SCEGE , " PackFramebufferD3D11_: vfb->fbo == 0 " ) ;
2017-05-16 13:53:57 +02:00
draw_ - > BindFramebufferAsRenderTarget ( nullptr ) ;
2017-02-08 18:07:34 +01:00
return ;
}
const u32 fb_address = ( 0x04000000 ) | vfb - > fb_address ;
const int dstBpp = vfb - > format = = GE_FORMAT_8888 ? 4 : 2 ;
// We always need to convert from the framebuffer native format.
// Right now that's always 8888.
2017-03-06 13:10:23 +01:00
DEBUG_LOG ( G3D , " Reading framebuffer to mem, fb_address = %08x " , fb_address ) ;
2017-02-14 12:42:35 +01:00
ID3D11Texture2D * colorTex = ( ID3D11Texture2D * ) draw_ - > GetFramebufferAPITexture ( vfb - > fbo , Draw : : FB_COLOR_BIT , 0 ) ;
2017-02-08 18:07:34 +01:00
2017-03-19 14:22:06 +01:00
// TODO: Only copy the necessary rectangle.
2017-03-20 07:21:54 -07:00
D3D11_BOX srcBox { ( UINT ) x , ( UINT ) y , 0 , ( UINT ) ( x + w ) , ( UINT ) ( y + h ) , 1 } ;
2017-03-19 14:57:48 +01:00
context_ - > CopySubresourceRegion ( packTexture_ , 0 , x , y , 0 , colorTex , 0 , & srcBox ) ;
2017-02-14 12:42:35 +01:00
// Ideally, we'd round robin between two packTexture_, and simply use the other one. Though if the game
// does a once-off copy, that won't work at all.
// BIG GPU STALL
D3D11_MAPPED_SUBRESOURCE map ;
HRESULT result = context_ - > Map ( packTexture_ , 0 , D3D11_MAP_READ , 0 , & map ) ;
if ( FAILED ( result ) ) {
return ;
2017-02-08 18:07:34 +01:00
}
2017-02-14 12:42:35 +01:00
// TODO: Handle the other formats? We don't currently create them, I think.
const int srcByteOffset = y * map . RowPitch + x * 4 ;
const int dstByteOffset = ( y * vfb - > fb_stride + x ) * dstBpp ;
// Pixel size always 4 here because we always request BGRA8888.
2017-03-19 14:22:06 +01:00
ConvertFromRGBA8888 ( Memory : : GetPointer ( fb_address + dstByteOffset ) , ( u8 * ) map . pData + srcByteOffset , vfb - > fb_stride , map . RowPitch / 4 , w , h , vfb - > format ) ;
2017-02-14 12:42:35 +01:00
context_ - > Unmap ( packTexture_ , 0 ) ;
2017-02-08 18:07:34 +01:00
}
2017-02-14 12:42:35 +01:00
// Nobody calls this yet.
2017-02-08 18:07:34 +01:00
void FramebufferManagerD3D11 : : PackDepthbuffer ( VirtualFramebuffer * vfb , int x , int y , int w , int h ) {
if ( ! vfb - > fbo ) {
ERROR_LOG_REPORT_ONCE ( vfbfbozero , SCEGE , " PackDepthbuffer: vfb->fbo == 0 " ) ;
return ;
}
const u32 z_address = ( 0x04000000 ) | vfb - > z_address ;
2017-02-14 12:42:35 +01:00
// TODO
2017-02-08 18:07:34 +01:00
}
void FramebufferManagerD3D11 : : EndFrame ( ) {
}
void FramebufferManagerD3D11 : : DeviceLost ( ) {
2017-04-13 23:07:21 -07:00
DestroyAllFBOs ( ) ;
2017-02-08 18:07:34 +01:00
}
std : : vector < FramebufferInfo > FramebufferManagerD3D11 : : GetFramebufferList ( ) {
std : : vector < FramebufferInfo > list ;
for ( size_t i = 0 ; i < vfbs_ . size ( ) ; + + i ) {
VirtualFramebuffer * vfb = vfbs_ [ i ] ;
FramebufferInfo info ;
info . fb_address = vfb - > fb_address ;
info . z_address = vfb - > z_address ;
info . format = vfb - > format ;
info . width = vfb - > width ;
info . height = vfb - > height ;
info . fbo = vfb - > fbo ;
list . push_back ( info ) ;
}
return list ;
}
2017-04-13 23:07:21 -07:00
void FramebufferManagerD3D11 : : DestroyAllFBOs ( ) {
2017-05-16 13:53:57 +02:00
draw_ - > BindFramebufferAsRenderTarget ( nullptr ) ;
2017-02-08 18:07:34 +01:00
currentRenderVfb_ = 0 ;
displayFramebuf_ = 0 ;
prevDisplayFramebuf_ = 0 ;
prevPrevDisplayFramebuf_ = 0 ;
for ( size_t i = 0 ; i < vfbs_ . size ( ) ; + + i ) {
VirtualFramebuffer * vfb = vfbs_ [ i ] ;
2017-03-13 12:32:21 +01:00
INFO_LOG ( FRAMEBUF , " Destroying FBO for %08x : %i x %i x %i " , vfb - > fb_address , vfb - > width , vfb - > height , vfb - > format ) ;
2017-02-08 18:07:34 +01:00
DestroyFramebuf ( vfb ) ;
}
vfbs_ . clear ( ) ;
for ( size_t i = 0 ; i < bvfbs_ . size ( ) ; + + i ) {
VirtualFramebuffer * vfb = bvfbs_ [ i ] ;
DestroyFramebuf ( vfb ) ;
}
bvfbs_ . clear ( ) ;
for ( auto it = tempFBOs_ . begin ( ) , end = tempFBOs_ . end ( ) ; it ! = end ; + + it ) {
delete it - > second . fbo ;
}
tempFBOs_ . clear ( ) ;
DisableState ( ) ;
}
void FramebufferManagerD3D11 : : FlushBeforeCopy ( ) {
// Flush anything not yet drawn before blitting, downloading, or uploading.
// This might be a stalled list, or unflushed before a block transfer, etc.
// TODO: It's really bad that we are calling SetRenderFramebuffer here with
// all the irrelevant state checking it'll use to decide what to do. Should
// do something more focused here.
SetRenderFrameBuffer ( gstate_c . IsDirty ( DIRTY_FRAMEBUF ) , gstate_c . skipDrawReason ) ;
drawEngine_ - > Flush ( ) ;
}
void FramebufferManagerD3D11 : : Resized ( ) {
2017-04-24 11:58:16 -07:00
FramebufferManagerCommon : : Resized ( ) ;
if ( UpdateSize ( ) ) {
DestroyAllFBOs ( ) ;
}
// Might have a new post shader - let's compile it.
CompilePostShader ( ) ;
2017-02-08 18:07:34 +01:00
}
2017-02-18 00:27:32 +01:00
// Lots of this code could be shared (like the downsampling).
2017-02-14 12:42:35 +01:00
bool FramebufferManagerD3D11 : : GetFramebuffer ( u32 fb_address , int fb_stride , GEBufferFormat format , GPUDebugBuffer & buffer , int maxRes ) {
2017-02-18 00:27:32 +01:00
VirtualFramebuffer * vfb = currentRenderVfb_ ;
if ( ! vfb ) {
vfb = GetVFBAt ( fb_address ) ;
}
if ( ! vfb ) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer ( Memory : : GetPointer ( fb_address | 0x04000000 ) , fb_stride , 512 , format ) ;
return true ;
}
int w = vfb - > renderWidth , h = vfb - > renderHeight ;
Draw : : Framebuffer * fboForRead = nullptr ;
if ( vfb - > fbo ) {
if ( maxRes > 0 & & vfb - > renderWidth > vfb - > width * maxRes ) {
w = vfb - > width * maxRes ;
h = vfb - > height * maxRes ;
Draw : : Framebuffer * tempFBO = GetTempFBO ( w , h ) ;
VirtualFramebuffer tempVfb = * vfb ;
tempVfb . fbo = tempFBO ;
tempVfb . bufferWidth = vfb - > width ;
tempVfb . bufferHeight = vfb - > height ;
tempVfb . renderWidth = w ;
tempVfb . renderHeight = h ;
BlitFramebuffer ( & tempVfb , 0 , 0 , vfb , 0 , 0 , vfb - > width , vfb - > height , 0 ) ;
fboForRead = tempFBO ;
} else {
fboForRead = vfb - > fbo ;
}
}
2017-02-18 03:00:22 +01:00
if ( ! fboForRead )
return false ;
2017-02-18 00:27:32 +01:00
buffer . Allocate ( w , h , GE_FORMAT_8888 , ! useBufferedRendering_ , true ) ;
ID3D11Texture2D * packTex ;
D3D11_TEXTURE2D_DESC packDesc { } ;
packDesc . CPUAccessFlags = D3D11_CPU_ACCESS_READ ;
packDesc . BindFlags = 0 ;
packDesc . Width = w ;
packDesc . Height = h ;
packDesc . ArraySize = 1 ;
packDesc . MipLevels = 1 ;
packDesc . Usage = D3D11_USAGE_STAGING ;
packDesc . SampleDesc . Count = 1 ;
packDesc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateTexture2D ( & packDesc , nullptr , & packTex ) ) ;
2017-02-18 00:27:32 +01:00
ID3D11Texture2D * nativeTex = ( ID3D11Texture2D * ) draw_ - > GetFramebufferAPITexture ( fboForRead , Draw : : FB_COLOR_BIT , 0 ) ;
context_ - > CopyResource ( packTex , nativeTex ) ;
D3D11_MAPPED_SUBRESOURCE map ;
context_ - > Map ( packTex , 0 , D3D11_MAP_READ , 0 , & map ) ;
for ( int y = 0 ; y < h ; y + + ) {
uint8_t * dest = ( uint8_t * ) buffer . GetData ( ) + y * w * 4 ;
const uint8_t * src = ( ( const uint8_t * ) map . pData ) + map . RowPitch * y ;
memcpy ( dest , src , 4 * w ) ;
}
context_ - > Unmap ( packTex , 0 ) ;
packTex - > Release ( ) ;
return true ;
2017-02-08 18:07:34 +01:00
}
2017-02-23 16:27:26 +01:00
bool FramebufferManagerD3D11 : : GetDepthStencilBuffer ( VirtualFramebuffer * vfb , GPUDebugBuffer & buffer , bool stencil ) {
int w = vfb - > renderWidth , h = vfb - > renderHeight ;
Draw : : Framebuffer * fboForRead = nullptr ;
fboForRead = vfb - > fbo ;
2017-03-19 07:45:00 -07:00
if ( stencil ) {
buffer . Allocate ( w , h , GPU_DBG_FORMAT_8BIT ) ;
} else if ( gstate_c . Supports ( GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT ) ) {
buffer . Allocate ( w , h , GPU_DBG_FORMAT_FLOAT_DIV_256 ) ;
2017-02-23 17:31:24 +01:00
} else {
2017-03-19 07:45:00 -07:00
buffer . Allocate ( w , h , GPU_DBG_FORMAT_FLOAT ) ;
2017-02-23 17:31:24 +01:00
}
2017-02-23 16:27:26 +01:00
ID3D11Texture2D * packTex ;
D3D11_TEXTURE2D_DESC packDesc { } ;
packDesc . CPUAccessFlags = D3D11_CPU_ACCESS_READ ;
packDesc . BindFlags = 0 ;
packDesc . Width = w ;
packDesc . Height = h ;
packDesc . ArraySize = 1 ;
packDesc . MipLevels = 1 ;
packDesc . Usage = D3D11_USAGE_STAGING ;
packDesc . SampleDesc . Count = 1 ;
packDesc . Format = ( DXGI_FORMAT ) draw_ - > GetFramebufferAPITexture ( fboForRead , Draw : : FB_DEPTH_BIT | Draw : : FB_FORMAT_BIT , 0 ) ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateTexture2D ( & packDesc , nullptr , & packTex ) ) ;
2017-02-23 16:27:26 +01:00
ID3D11Texture2D * nativeTex = ( ID3D11Texture2D * ) draw_ - > GetFramebufferAPITexture ( fboForRead , Draw : : FB_DEPTH_BIT , 0 ) ;
context_ - > CopyResource ( packTex , nativeTex ) ;
D3D11_MAPPED_SUBRESOURCE map ;
context_ - > Map ( packTex , 0 , D3D11_MAP_READ , 0 , & map ) ;
for ( int y = 0 ; y < h ; y + + ) {
float * dest = ( float * ) ( buffer . GetData ( ) + y * w * 4 ) ;
2017-03-19 07:45:00 -07:00
u8 * destStencil = buffer . GetData ( ) + y * w ;
2017-02-23 16:27:26 +01:00
const uint32_t * src = ( const uint32_t * ) ( ( const uint8_t * ) map . pData + map . RowPitch * y ) ;
for ( int x = 0 ; x < w ; x + + ) {
if ( stencil ) {
2017-03-19 07:45:00 -07:00
destStencil [ x ] = src [ x ] > > 24 ;
2017-02-23 16:27:26 +01:00
} else {
dest [ x ] = ( src [ x ] & 0xFFFFFF ) / ( 256.f * 256.f * 256.f ) ;
}
}
}
context_ - > Unmap ( packTex , 0 ) ;
packTex - > Release ( ) ;
return true ;
}
2017-02-14 12:42:35 +01:00
bool FramebufferManagerD3D11 : : GetDepthbuffer ( u32 fb_address , int fb_stride , u32 z_address , int z_stride , GPUDebugBuffer & buffer ) {
2017-02-23 16:27:26 +01:00
VirtualFramebuffer * vfb = currentRenderVfb_ ;
if ( ! vfb ) {
vfb = GetVFBAt ( fb_address ) ;
}
if ( ! vfb ) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer ( Memory : : GetPointer ( z_address | 0x04000000 ) , z_stride , 512 , GPU_DBG_FORMAT_16BIT ) ;
return true ;
}
if ( ! vfb - > fbo ) {
return false ;
}
return GetDepthStencilBuffer ( vfb , buffer , false ) ;
2017-02-08 18:07:34 +01:00
}
2017-02-14 12:42:35 +01:00
bool FramebufferManagerD3D11 : : GetStencilbuffer ( u32 fb_address , int fb_stride , GPUDebugBuffer & buffer ) {
2017-02-23 16:27:26 +01:00
VirtualFramebuffer * vfb = currentRenderVfb_ ;
if ( ! vfb ) {
vfb = GetVFBAt ( fb_address ) ;
}
if ( ! vfb ) {
return false ;
}
if ( ! vfb - > fbo ) {
return false ;
}
return GetDepthStencilBuffer ( vfb , buffer , true ) ;
2017-02-08 18:07:34 +01:00
}
2017-02-14 12:42:35 +01:00
bool FramebufferManagerD3D11 : : GetOutputFramebuffer ( GPUDebugBuffer & buffer ) {
2017-02-18 00:43:02 +01:00
ID3D11Texture2D * backbuffer = ( ID3D11Texture2D * ) draw_ - > GetNativeObject ( Draw : : NativeObject : : BACKBUFFER_COLOR_TEX ) ;
2017-03-05 20:30:39 +01:00
if ( ! backbuffer ) {
ERROR_LOG ( G3D , " Failed to get backbuffer from draw context " ) ;
return false ;
}
2017-02-18 00:43:02 +01:00
D3D11_TEXTURE2D_DESC desc ;
backbuffer - > GetDesc ( & desc ) ;
int w = desc . Width ;
int h = desc . Height ;
buffer . Allocate ( w , h , GE_FORMAT_8888 , ! useBufferedRendering_ , true ) ;
ID3D11Texture2D * packTex ;
D3D11_TEXTURE2D_DESC packDesc { } ;
packDesc . CPUAccessFlags = D3D11_CPU_ACCESS_READ ;
packDesc . BindFlags = 0 ;
packDesc . Width = w ;
packDesc . Height = h ;
packDesc . ArraySize = 1 ;
packDesc . MipLevels = 1 ;
packDesc . Usage = D3D11_USAGE_STAGING ;
packDesc . SampleDesc . Count = 1 ;
packDesc . Format = DXGI_FORMAT_R8G8B8A8_UNORM ;
2017-03-05 10:33:35 +01:00
ASSERT_SUCCESS ( device_ - > CreateTexture2D ( & packDesc , nullptr , & packTex ) ) ;
2017-02-18 00:43:02 +01:00
context_ - > CopyResource ( packTex , backbuffer ) ;
D3D11_MAPPED_SUBRESOURCE map ;
context_ - > Map ( packTex , 0 , D3D11_MAP_READ , 0 , & map ) ;
for ( int y = 0 ; y < h ; y + + ) {
uint8_t * dest = ( uint8_t * ) buffer . GetData ( ) + y * w * 4 ;
const uint8_t * src = ( ( const uint8_t * ) map . pData ) + map . RowPitch * y ;
memcpy ( dest , src , 4 * w ) ;
}
context_ - > Unmap ( packTex , 0 ) ;
packTex - > Release ( ) ;
return true ;
2017-02-14 12:42:35 +01:00
}