2013-08-17 11:23:51 +02:00
// Copyright (c) 2012- 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/.
# include "math/lin/matrix4x4.h"
2017-02-04 18:46:12 +01:00
# include "ext/native/thin3d/thin3d.h"
2015-04-08 00:16:22 +02:00
# include "Common/ColorConv.h"
2013-08-17 11:23:51 +02:00
# include "Core/Host.h"
# include "Core/MemMap.h"
# include "Core/Config.h"
2018-06-16 18:42:31 -07:00
# include "Core/ConfigValues.h"
2013-08-17 11:23:51 +02:00
# include "Core/System.h"
2013-11-15 14:24:25 +01:00
# include "Core/Reporting.h"
2013-08-17 11:23:51 +02:00
# include "GPU/ge_constants.h"
# include "GPU/GPUState.h"
2014-09-17 23:26:20 +02:00
# include "GPU/Debugger/Stepping.h"
2013-08-17 11:23:51 +02:00
2017-02-05 20:54:24 +01:00
# include "gfx/d3d9_state.h"
2014-09-09 08:12:42 -07:00
# include "GPU/Common/FramebufferCommon.h"
2014-09-13 16:37:59 -07:00
# include "GPU/Common/TextureDecoder.h"
2013-09-15 12:46:14 +02:00
# include "GPU/Directx9/FramebufferDX9.h"
# include "GPU/Directx9/ShaderManagerDX9.h"
2014-09-13 14:23:18 -07:00
# include "GPU/Directx9/TextureCacheDX9.h"
2016-04-10 10:55:13 +02:00
# include "GPU/Directx9/DrawEngineDX9.h"
2013-08-17 11:23:51 +02:00
2017-02-05 20:46:26 +01:00
# include "ext/native/thin3d/thin3d.h"
2013-09-17 00:48:14 -04:00
# include <algorithm>
2016-01-31 09:00:00 -08:00
# ifdef _M_SSE
2017-03-12 17:16:38 +01:00
# include <emmintrin.h>
2016-01-31 09:00:00 -08:00
# endif
2013-09-15 08:53:21 -07:00
namespace DX9 {
2017-02-05 19:42:54 +01:00
static const char * vscode =
" struct VS_IN { \n "
" float4 ObjPos : POSITION; \n "
" float2 Uv : TEXCOORD0; \n "
" }; "
" struct VS_OUT { \n "
" float4 ProjPos : POSITION; \n "
" float2 Uv : TEXCOORD0; \n "
" }; \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 " ;
//--------------------------------------------------------------------------------------
// Pixel shader
//--------------------------------------------------------------------------------------
static const char * pscode =
" sampler s: register(s0); \n "
" struct PS_IN { \n "
" float2 Uv : TEXCOORD0; \n "
" }; \n "
" float4 main( PS_IN In ) : COLOR { \n "
" float4 c = tex2D(s, In.Uv); \n "
" return c; \n "
" } \n " ;
2013-08-17 11:23:51 +02:00
2017-02-05 20:13:28 +01:00
static const D3DVERTEXELEMENT9 g_FramebufferVertexElements [ ] = {
{ 0 , 0 , D3DDECLTYPE_FLOAT3 , D3DDECLMETHOD_DEFAULT , D3DDECLUSAGE_POSITION , 0 } ,
{ 0 , 12 , D3DDECLTYPE_FLOAT2 , D3DDECLMETHOD_DEFAULT , D3DDECLUSAGE_TEXCOORD , 0 } ,
D3DDECL_END ( )
} ;
2017-02-05 19:51:50 +01:00
FramebufferManagerDX9 : : FramebufferManagerDX9 ( Draw : : DrawContext * draw )
2018-06-03 07:45:21 -07:00
: FramebufferManagerCommon ( draw ) {
2017-02-05 19:42:54 +01:00
2017-02-05 20:46:26 +01:00
device_ = ( LPDIRECT3DDEVICE9 ) draw - > GetNativeObject ( Draw : : NativeObject : : DEVICE ) ;
2017-03-02 11:39:02 +01:00
deviceEx_ = ( LPDIRECT3DDEVICE9 ) draw - > GetNativeObject ( Draw : : NativeObject : : DEVICE_EX ) ;
2017-02-05 19:42:54 +01:00
std : : string errorMsg ;
2017-02-05 20:46:26 +01:00
if ( ! CompileVertexShader ( device_ , vscode , & pFramebufferVertexShader , nullptr , errorMsg ) ) {
2017-02-05 19:42:54 +01:00
OutputDebugStringA ( errorMsg . c_str ( ) ) ;
}
2017-02-05 20:46:26 +01:00
if ( ! CompilePixelShader ( device_ , pscode , & pFramebufferPixelShader , nullptr , errorMsg ) ) {
2017-02-05 19:42:54 +01:00
OutputDebugStringA ( errorMsg . c_str ( ) ) ;
if ( pFramebufferVertexShader ) {
pFramebufferVertexShader - > Release ( ) ;
}
}
2017-02-05 20:13:28 +01:00
2017-03-02 11:39:02 +01:00
device_ - > CreateVertexDeclaration ( g_FramebufferVertexElements , & pFramebufferVertexDecl ) ;
2018-08-30 21:00:21 -07:00
int usage = 0 ;
D3DPOOL pool = D3DPOOL_MANAGED ;
if ( deviceEx_ ) {
pool = D3DPOOL_DEFAULT ;
usage = D3DUSAGE_DYNAMIC ;
}
HRESULT hr = device_ - > CreateTexture ( 1 , 1 , 1 , usage , D3DFMT_A8R8G8B8 , pool , & nullTex_ , nullptr ) ;
D3DLOCKED_RECT rect ;
nullTex_ - > LockRect ( 0 , & rect , nullptr , D3DLOCK_DISCARD ) ;
memset ( rect . pBits , 0 , 4 ) ;
nullTex_ - > UnlockRect ( 0 ) ;
2013-11-15 14:24:25 +01:00
}
FramebufferManagerDX9 : : ~ FramebufferManagerDX9 ( ) {
2017-02-05 19:42:54 +01:00
if ( pFramebufferVertexShader ) {
pFramebufferVertexShader - > Release ( ) ;
pFramebufferVertexShader = nullptr ;
}
if ( pFramebufferPixelShader ) {
pFramebufferPixelShader - > Release ( ) ;
pFramebufferPixelShader = nullptr ;
}
2017-02-05 20:13:28 +01:00
pFramebufferVertexDecl - > Release ( ) ;
2014-09-13 19:56:08 -07:00
if ( drawPixelsTex_ ) {
2013-11-15 14:24:25 +01:00
drawPixelsTex_ - > Release ( ) ;
}
2018-06-03 07:45:21 -07:00
for ( auto & it : offscreenSurfaces_ ) {
it . second . surface - > Release ( ) ;
2014-09-13 22:28:39 -07:00
}
2013-11-15 14:24:25 +01:00
delete [ ] convBuf ;
2014-09-14 02:21:41 -07:00
if ( stencilUploadPS_ ) {
stencilUploadPS_ - > Release ( ) ;
}
if ( stencilUploadVS_ ) {
stencilUploadVS_ - > Release ( ) ;
}
2018-08-30 21:00:21 -07:00
if ( nullTex_ )
nullTex_ - > Release ( ) ;
2013-11-15 14:24:25 +01:00
}
2017-02-06 12:02:30 +01:00
void FramebufferManagerDX9 : : SetTextureCache ( TextureCacheDX9 * tc ) {
textureCacheDX9_ = tc ;
textureCache_ = tc ;
}
2017-02-15 18:32:44 +01:00
void FramebufferManagerDX9 : : SetShaderManager ( ShaderManagerDX9 * sm ) {
shaderManagerDX9_ = sm ;
shaderManager_ = sm ;
}
2017-10-18 12:26:02 +02:00
void FramebufferManagerDX9 : : SetDrawEngine ( DrawEngineDX9 * td ) {
drawEngineD3D9_ = td ;
drawEngine_ = td ;
}
2017-03-22 20:56:26 -07:00
void FramebufferManagerDX9 : : MakePixelTexture ( const u8 * srcPixels , GEBufferFormat srcPixelFormat , int srcStride , int width , int height , float & u1 , float & v1 ) {
2014-09-13 13:09:26 -07:00
u8 * convBuf = NULL ;
2013-11-15 14:24:25 +01:00
D3DLOCKED_RECT rect ;
2013-08-19 20:36:43 +02:00
2014-09-13 19:56:08 -07:00
// TODO: Check / use D3DCAPS2_DYNAMICTEXTURES?
if ( drawPixelsTex_ & & ( drawPixelsTexW_ ! = width | | drawPixelsTexH_ ! = height ) ) {
drawPixelsTex_ - > Release ( ) ;
drawPixelsTex_ = nullptr ;
}
if ( ! drawPixelsTex_ ) {
int usage = 0 ;
D3DPOOL pool = D3DPOOL_MANAGED ;
2017-03-02 11:39:02 +01:00
if ( deviceEx_ ) {
2014-09-13 19:56:08 -07:00
pool = D3DPOOL_DEFAULT ;
usage = D3DUSAGE_DYNAMIC ;
}
2017-03-02 11:39:02 +01:00
HRESULT hr = device_ - > CreateTexture ( width , height , 1 , usage , D3DFMT_A8R8G8B8 , pool , & drawPixelsTex_ , NULL ) ;
2014-09-13 19:56:08 -07:00
if ( FAILED ( hr ) ) {
drawPixelsTex_ = nullptr ;
ERROR_LOG ( G3D , " Failed to create drawpixels texture " ) ;
}
2014-09-13 21:45:18 -07:00
drawPixelsTexW_ = width ;
drawPixelsTexH_ = height ;
2014-09-13 19:56:08 -07:00
}
2014-09-09 22:28:35 +02:00
if ( ! drawPixelsTex_ ) {
return ;
}
2017-02-21 11:35:06 +01:00
drawPixelsTex_ - > LockRect ( 0 , & rect , NULL , D3DLOCK_DISCARD ) ;
2013-08-19 20:36:43 +02:00
2013-11-15 14:24:25 +01:00
convBuf = ( u8 * ) rect . pBits ;
2013-08-17 11:23:51 +02:00
2014-09-13 14:53:14 -07:00
// Final format is BGRA(directx)
2014-09-13 13:09:26 -07:00
if ( srcPixelFormat ! = GE_FORMAT_8888 | | srcStride ! = 512 ) {
2014-09-13 14:54:53 -07:00
for ( int y = 0 ; y < height ; y + + ) {
2014-09-13 13:09:26 -07:00
switch ( srcPixelFormat ) {
2013-11-15 14:24:25 +01:00
case GE_FORMAT_565 :
{
2014-09-13 14:53:14 -07:00
const u16_le * src = ( const u16_le * ) srcPixels + srcStride * y ;
u32 * dst = ( u32 * ) ( convBuf + rect . Pitch * y ) ;
2015-05-25 10:47:37 -07:00
ConvertRGB565ToBGRA8888 ( dst , src , width ) ;
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
break ;
2015-01-22 19:53:32 +01:00
// faster
2013-11-15 14:24:25 +01:00
case GE_FORMAT_5551 :
{
2014-09-13 14:53:14 -07:00
const u16_le * src = ( const u16_le * ) srcPixels + srcStride * y ;
u32 * dst = ( u32 * ) ( convBuf + rect . Pitch * y ) ;
2015-05-25 10:47:37 -07:00
ConvertRGBA5551ToBGRA8888 ( dst , src , width ) ;
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
break ;
case GE_FORMAT_4444 :
2013-08-17 11:23:51 +02:00
{
2014-09-13 14:53:14 -07:00
const u16_le * src = ( const u16_le * ) srcPixels + srcStride * y ;
2015-01-22 19:53:32 +01:00
u8 * dst = ( u8 * ) ( convBuf + rect . Pitch * y ) ;
2015-05-25 10:47:37 -07:00
ConvertRGBA4444ToBGRA8888 ( ( u32 * ) dst , src , width ) ;
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
break ;
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
case GE_FORMAT_8888 :
2013-08-24 19:07:15 +02:00
{
2014-09-13 14:53:14 -07:00
const u32_le * src = ( const u32_le * ) srcPixels + srcStride * y ;
u32 * dst = ( u32 * ) ( convBuf + rect . Pitch * y ) ;
2015-05-25 10:47:37 -07:00
ConvertRGBA8888ToBGRA8888 ( dst , src , width ) ;
2013-08-24 19:07:15 +02:00
}
2013-11-15 14:24:25 +01:00
break ;
2013-08-17 11:23:51 +02:00
}
}
2013-11-15 14:24:25 +01:00
} else {
2014-09-13 14:54:53 -07:00
for ( int y = 0 ; y < height ; y + + ) {
2014-09-13 14:53:14 -07:00
const u32_le * src = ( const u32_le * ) srcPixels + srcStride * y ;
u32 * dst = ( u32 * ) ( convBuf + rect . Pitch * y ) ;
2015-05-25 10:47:37 -07:00
ConvertRGBA8888ToBGRA8888 ( dst , src , width ) ;
2013-08-24 19:07:15 +02:00
}
}
2013-08-23 11:07:39 +02:00
2013-11-15 14:24:25 +01:00
drawPixelsTex_ - > UnlockRect ( 0 ) ;
2017-02-06 12:22:32 +01:00
device_ - > SetTexture ( 0 , drawPixelsTex_ ) ;
2017-02-15 18:32:44 +01:00
// D3DXSaveTextureToFile("game:\\cc.png", D3DXIFF_PNG, drawPixelsTex_, NULL);
2014-09-13 13:09:26 -07:00
}
2017-02-15 13:05:10 +01:00
void FramebufferManagerDX9 : : SetViewport2D ( int x , int y , int w , int h ) {
D3DVIEWPORT9 vp { ( DWORD ) x , ( DWORD ) y , ( DWORD ) w , ( DWORD ) h , 0.0f , 1.0f } ;
2017-03-02 11:39:02 +01:00
device_ - > SetViewport ( & vp ) ;
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
2017-05-31 23:24:56 -07:00
void FramebufferManagerDX9 : : DrawActiveTexture ( float x , float y , float w , float h , float destW , float destH , float u0 , float v0 , float u1 , float v1 , int uvRotation , int flags ) {
2018-02-08 16:21:41 +01:00
// TODO: StretchRect instead when possible?
2014-09-13 13:09:26 -07:00
float coord [ 20 ] = {
x , y , 0 , u0 , v0 ,
x + w , y , 0 , u1 , v0 ,
x + w , y + h , 0 , u1 , v1 ,
x , y + h , 0 , u0 , v1 ,
} ;
2013-11-15 14:24:25 +01:00
2015-05-12 21:01:15 +02: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 + + ) {
temp [ i * 2 ] = coord [ ( ( i + rotation ) & 3 ) * 5 + 3 ] ;
temp [ i * 2 + 1 ] = coord [ ( ( i + rotation ) & 3 ) * 5 + 4 ] ;
}
for ( int i = 0 ; i < 4 ; i + + ) {
coord [ i * 5 + 3 ] = temp [ i * 2 ] ;
coord [ i * 5 + 4 ] = temp [ i * 2 + 1 ] ;
}
}
2014-09-13 13:09:26 -07:00
float invDestW = 1.0f / ( destW * 0.5f ) ;
float invDestH = 1.0f / ( destH * 0.5f ) ;
2014-09-20 07:53:16 -07:00
float halfPixelX = invDestW * 0.5f ;
float halfPixelY = invDestH * 0.5f ;
2013-11-15 14:24:25 +01:00
for ( int i = 0 ; i < 4 ; i + + ) {
2014-12-30 15:25:40 -08:00
coord [ i * 5 ] = coord [ i * 5 ] * invDestW - 1.0f - halfPixelX ;
2014-09-20 07:53:16 -07:00
coord [ i * 5 + 1 ] = - ( coord [ i * 5 + 1 ] * invDestH - 1.0f - halfPixelY ) ;
2013-11-15 14:24:25 +01:00
}
2017-05-31 23:24:56 -07:00
if ( flags & DRAWTEX_LINEAR ) {
2017-02-15 12:50:15 +01:00
dxstate . texMagFilter . set ( D3DTEXF_LINEAR ) ;
dxstate . texMinFilter . set ( D3DTEXF_LINEAR ) ;
} else {
dxstate . texMagFilter . set ( D3DTEXF_POINT ) ;
dxstate . texMinFilter . set ( D3DTEXF_POINT ) ;
}
2017-04-22 18:36:25 -07:00
dxstate . texMipLodBias . set ( 0.0f ) ;
dxstate . texMaxMipLevel . set ( 0 ) ;
2018-02-08 16:21:41 +01:00
dxstate . blend . disable ( ) ;
dxstate . cullMode . set ( false , false ) ;
dxstate . depthTest . disable ( ) ;
dxstate . scissorTest . disable ( ) ;
dxstate . stencilTest . disable ( ) ;
dxstate . colorMask . set ( true , true , true , true ) ;
dxstate . stencilMask . set ( 0xFF ) ;
2017-03-02 11:39:02 +01:00
HRESULT hr = device_ - > DrawPrimitiveUP ( D3DPT_TRIANGLEFAN , 2 , coord , 5 * sizeof ( float ) ) ;
2014-09-13 19:21:59 -07:00
if ( FAILED ( hr ) ) {
ERROR_LOG_REPORT ( G3D , " DrawActiveTexture() failed: %08x " , hr ) ;
}
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
2017-02-15 16:01:59 +01:00
void FramebufferManagerDX9 : : Bind2DShader ( ) {
2017-03-02 11:39:02 +01:00
device_ - > SetVertexDeclaration ( pFramebufferVertexDecl ) ;
device_ - > SetPixelShader ( pFramebufferPixelShader ) ;
device_ - > SetVertexShader ( pFramebufferVertexShader ) ;
2017-02-15 16:01:59 +01:00
}
2017-02-15 23:24:25 +01:00
void FramebufferManagerDX9 : : BindPostShader ( const PostShaderUniforms & uniforms ) {
Bind2DShader ( ) ;
}
2015-02-26 08:41:10 -08:00
void FramebufferManagerDX9 : : ReformatFramebufferFrom ( VirtualFramebuffer * vfb , GEBufferFormat old ) {
2017-02-04 18:46:12 +01:00
if ( ! useBufferedRendering_ | | ! vfb - > fbo ) {
2015-02-26 08:41:10 -08:00
return ;
}
// 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.
2018-08-30 21:00:21 -07:00
// (it uses 565 to write zeros to the buffer, then 4444 to actually render the shadow.)
2015-02-26 08:41:10 -08:00
//
// 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 ) {
2018-08-30 21:00:21 -07:00
draw_ - > BindFramebufferAsRenderTarget ( vfb - > fbo , { Draw : : RPAction : : KEEP , Draw : : RPAction : : KEEP , Draw : : RPAction : : CLEAR } ) ;
2015-02-26 08:41:10 -08:00
dxstate . scissorTest . disable ( ) ;
dxstate . depthWrite . set ( FALSE ) ;
dxstate . colorMask . set ( false , false , false , true ) ;
dxstate . stencilFunc . set ( D3DCMP_ALWAYS , 0 , 0 ) ;
dxstate . stencilMask . set ( 0xFF ) ;
2018-08-30 21:00:21 -07:00
gstate_c . Dirty ( DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE ) ;
2015-02-26 08:41:10 -08:00
float coord [ 20 ] = {
- 1.0f , - 1.0f , 0 , 0 , 0 ,
1.0f , - 1.0f , 0 , 0 , 0 ,
1.0f , 1.0f , 0 , 0 , 0 ,
- 1.0f , 1.0f , 0 , 0 , 0 ,
} ;
dxstate . cullMode . set ( false , false ) ;
2017-03-02 11:39:02 +01:00
device_ - > SetVertexDeclaration ( pFramebufferVertexDecl ) ;
device_ - > SetPixelShader ( pFramebufferPixelShader ) ;
device_ - > SetVertexShader ( pFramebufferVertexShader ) ;
2017-02-15 18:32:44 +01:00
shaderManagerDX9_ - > DirtyLastShader ( ) ;
2018-08-30 21:00:21 -07:00
device_ - > SetTexture ( 0 , nullTex_ ) ;
2015-02-26 08:41:10 -08:00
2017-03-02 11:39:02 +01:00
D3DVIEWPORT9 vp { 0 , 0 , ( DWORD ) vfb - > renderWidth , ( DWORD ) vfb - > renderHeight , 0.0f , 1.0f } ;
device_ - > SetViewport ( & vp ) ;
2015-04-18 17:40:21 -07:00
2015-02-26 08:41:10 -08:00
// This should clear stencil and alpha without changing the other colors.
2017-03-02 11:39:02 +01:00
HRESULT hr = device_ - > DrawPrimitiveUP ( D3DPT_TRIANGLEFAN , 2 , coord , 5 * sizeof ( float ) ) ;
2015-02-26 08:41:10 -08:00
if ( FAILED ( hr ) ) {
ERROR_LOG_REPORT ( G3D , " ReformatFramebufferFrom() failed: %08x " , hr ) ;
}
2015-11-12 14:47:43 +01:00
dxstate . viewport . restore ( ) ;
2015-02-26 08:41:10 -08:00
2018-08-30 21:00:21 -07:00
textureCache_ - > ForgetLastTexture ( ) ;
}
2015-02-26 08:41:10 -08:00
}
2016-01-31 09:00:00 -08:00
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 ) ;
}
}
2014-09-14 11:54:55 -07:00
void FramebufferManagerDX9 : : BlitFramebufferDepth ( VirtualFramebuffer * src , VirtualFramebuffer * dst ) {
2016-02-10 21:02:19 -08:00
if ( g_Config . bDisableSlowFramebufEffects ) {
return ;
}
2016-01-30 22:56:24 -08:00
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 ;
if ( matchingDepthBuffer & & matchingSize ) {
2017-06-01 20:57:08 -07:00
// Should use StretchRect here? Note: should only copy depth and NOT copy stencil. See #9740.
2014-09-14 11:54:55 -07:00
}
}
2015-06-21 12:50:02 -07:00
LPDIRECT3DSURFACE9 FramebufferManagerDX9 : : GetOffscreenSurface ( LPDIRECT3DSURFACE9 similarSurface , VirtualFramebuffer * vfb ) {
D3DSURFACE_DESC desc = { } ;
HRESULT hr = similarSurface - > GetDesc ( & desc ) ;
if ( FAILED ( hr ) ) {
ERROR_LOG_REPORT ( G3D , " Unable to get size for offscreen surface at %08x " , vfb - > fb_address ) ;
return nullptr ;
}
2014-09-13 22:28:39 -07:00
2016-06-12 07:09:01 -07:00
return GetOffscreenSurface ( desc . Format , desc . Width , desc . Height ) ;
}
LPDIRECT3DSURFACE9 FramebufferManagerDX9 : : GetOffscreenSurface ( D3DFORMAT fmt , u32 w , u32 h ) {
u64 key = ( ( u64 ) fmt < < 32 ) | ( w < < 16 ) | h ;
2014-09-13 22:28:39 -07:00
auto it = offscreenSurfaces_ . find ( key ) ;
if ( it ! = offscreenSurfaces_ . end ( ) ) {
it - > second . last_frame_used = gpuStats . numFlips ;
return it - > second . surface ;
}
2017-02-06 12:02:30 +01:00
textureCacheDX9_ - > ForgetLastTexture ( ) ;
2014-09-13 22:28:39 -07:00
LPDIRECT3DSURFACE9 offscreen = nullptr ;
2017-03-02 11:39:02 +01:00
HRESULT hr = device_ - > CreateOffscreenPlainSurface ( w , h , fmt , D3DPOOL_SYSTEMMEM , & offscreen , NULL ) ;
2014-09-13 22:28:39 -07:00
if ( FAILED ( hr ) | | ! offscreen ) {
2016-06-12 07:09:01 -07:00
ERROR_LOG_REPORT ( G3D , " Unable to create offscreen surface %dx%d @%d " , w , h , fmt ) ;
2014-09-13 22:28:39 -07:00
return nullptr ;
}
const OffscreenSurface info = { offscreen , gpuStats . numFlips } ;
offscreenSurfaces_ [ key ] = info ;
return offscreen ;
}
2017-02-17 14:30:42 +01:00
void FramebufferManagerDX9 : : BindFramebufferAsColorTexture ( int stage , VirtualFramebuffer * framebuffer , int flags ) {
2014-09-17 23:26:20 +02:00
if ( framebuffer = = NULL ) {
framebuffer = currentRenderVfb_ ;
}
if ( ! framebuffer - > fbo | | ! useBufferedRendering_ ) {
2017-03-02 11:39:02 +01:00
device_ - > SetTexture ( stage , nullptr ) ;
2014-09-17 23:26:20 +02: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.
2015-09-13 11:14:51 -07:00
bool skipCopy = ( flags & BINDFBCOLOR_MAY_COPY ) = = 0 ;
2014-09-17 23:26:20 +02:00
if ( GPUStepping : : IsStepping ( ) | | g_Config . bDisableSlowFramebufEffects ) {
skipCopy = true ;
}
2018-11-22 09:26:12 -08:00
if ( ! skipCopy & & framebuffer = = currentRenderVfb_ ) {
2014-09-17 23:26:20 +02:00
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
2018-05-06 08:57:44 -07:00
Draw : : Framebuffer * renderCopy = GetTempFBO ( TempFBO : : COPY , framebuffer - > renderWidth , framebuffer - > renderHeight , ( Draw : : FBColorDepth ) framebuffer - > colorDepth ) ;
2014-09-17 23:26:20 +02:00
if ( renderCopy ) {
VirtualFramebuffer copyInfo = * framebuffer ;
2017-02-04 18:46:12 +01:00
copyInfo . fbo = renderCopy ;
2015-09-13 11:14:51 -07:00
2017-04-06 18:49:48 -07:00
CopyFramebufferForColorTexture ( & copyInfo , framebuffer , flags ) ;
2014-09-17 23:26:20 +02:00
RebindFramebuffer ( ) ;
2017-02-06 11:26:24 +01:00
draw_ - > BindFramebufferAsTexture ( renderCopy , stage , Draw : : FB_COLOR_BIT , 0 ) ;
2014-09-17 23:26:20 +02:00
} else {
2017-02-06 11:26:24 +01:00
draw_ - > BindFramebufferAsTexture ( framebuffer - > fbo , stage , Draw : : FB_COLOR_BIT , 0 ) ;
2014-09-17 23:26:20 +02:00
}
} else {
2017-02-06 11:26:24 +01:00
draw_ - > BindFramebufferAsTexture ( framebuffer - > fbo , stage , Draw : : FB_COLOR_BIT , 0 ) ;
2014-09-17 23:26:20 +02:00
}
}
2016-01-04 20:51:43 -08:00
bool FramebufferManagerDX9 : : CreateDownloadTempBuffer ( VirtualFramebuffer * nvfb ) {
2017-02-04 18:46:12 +01:00
nvfb - > colorDepth = Draw : : FBO_8888 ;
2016-01-04 20:51:43 -08:00
2018-06-01 21:16:07 +02:00
nvfb - > fbo = draw_ - > CreateFramebuffer ( { nvfb - > bufferWidth , nvfb - > bufferHeight , 1 , 1 , true , ( Draw : : FBColorDepth ) nvfb - > colorDepth } ) ;
2017-02-04 18:46:12 +01:00
if ( ! ( nvfb - > fbo ) ) {
2017-03-13 12:32:21 +01:00
ERROR_LOG ( FRAMEBUF , " Error creating FBO! %i x %i " , nvfb - > renderWidth , nvfb - > renderHeight ) ;
2016-01-04 20:51:43 -08:00
return false ;
}
2017-12-30 22:52:22 +01:00
draw_ - > BindFramebufferAsRenderTarget ( nvfb - > fbo , { Draw : : RPAction : : CLEAR , Draw : : RPAction : : CLEAR , Draw : : RPAction : : CLEAR } ) ;
2016-01-04 20:51:43 -08:00
return true ;
}
void FramebufferManagerDX9 : : UpdateDownloadTempBuffer ( VirtualFramebuffer * nvfb ) {
// Nothing to do here.
}
2015-11-01 13:32:03 +01:00
void FramebufferManagerDX9 : : BlitFramebuffer ( VirtualFramebuffer * dst , int dstX , int dstY , VirtualFramebuffer * src , int srcX , int srcY , int w , int h , int bpp ) {
2014-09-13 13:09:26 -07:00
if ( ! dst - > fbo | | ! src - > fbo | | ! useBufferedRendering_ ) {
2017-02-14 12:42:35 +01:00
// This can happen if we recently switched from non-buffered.
2017-05-16 16:00:34 +02:00
if ( useBufferedRendering_ )
2017-12-30 22:52:22 +01:00
draw_ - > BindFramebufferAsRenderTarget ( nullptr , { Draw : : RPAction : : KEEP , Draw : : RPAction : : KEEP , Draw : : RPAction : : KEEP } ) ;
2013-11-15 14:24:25 +01:00
return ;
}
2013-08-20 18:46:57 +02:00
2015-11-01 13:32:03 +01:00
float srcXFactor = ( float ) src - > renderWidth / ( float ) src - > bufferWidth ;
float srcYFactor = ( float ) src - > renderHeight / ( float ) src - > bufferHeight ;
2014-09-13 13:09:26 -07:00
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 ;
2014-09-13 17:10:57 -07:00
int srcY1 = srcY * srcYFactor ;
int srcY2 = ( srcY + h ) * srcYFactor ;
2014-09-13 13:09:26 -07:00
2015-11-01 13:32:03 +01:00
float dstXFactor = ( float ) dst - > renderWidth / ( float ) dst - > bufferWidth ;
float dstYFactor = ( float ) dst - > renderHeight / ( float ) dst - > bufferHeight ;
2014-09-13 13:09:26 -07:00
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 ;
2014-09-13 17:10:57 -07:00
int dstY1 = dstY * dstYFactor ;
int dstY2 = ( dstY + h ) * dstYFactor ;
2014-09-13 13:09:26 -07:00
2015-11-01 13:32:03 +01:00
// Direct3D 9 doesn't support rect -> self.
2017-02-04 18:46:12 +01:00
Draw : : Framebuffer * srcFBO = src - > fbo ;
2015-11-01 13:32:03 +01:00
if ( src = = dst ) {
2018-05-06 08:57:44 -07:00
Draw : : Framebuffer * tempFBO = GetTempFBO ( TempFBO : : BLIT , src - > renderWidth , src - > renderHeight , ( Draw : : FBColorDepth ) src - > colorDepth ) ;
2017-02-06 11:26:24 +01:00
bool result = draw_ - > BlitFramebuffer (
2017-02-04 18:46:12 +01:00
src - > fbo , srcX1 , srcY1 , srcX2 , srcY2 ,
2017-02-04 16:19:54 +01:00
tempFBO , dstX1 , dstY1 , dstX2 , dstY2 ,
2017-02-04 18:46:12 +01:00
Draw : : FB_COLOR_BIT , Draw : : FB_BLIT_NEAREST ) ;
if ( result ) {
2015-11-01 13:32:03 +01:00
srcFBO = tempFBO ;
2014-09-13 22:39:54 -07:00
}
2015-11-01 13:32:03 +01:00
}
2017-02-06 11:26:24 +01:00
bool result = draw_ - > BlitFramebuffer (
2017-02-04 16:19:54 +01:00
srcFBO , srcX1 , srcY1 , srcX2 , srcY2 ,
2017-02-04 18:46:12 +01:00
dst - > fbo , dstX1 , dstY1 , dstX2 , dstY2 ,
Draw : : FB_COLOR_BIT , Draw : : FB_BLIT_NEAREST ) ;
if ( ! result ) {
2017-03-12 23:00:12 -07:00
ERROR_LOG_REPORT ( G3D , " fbo_blit_color failed in blit (%08x -> %08x) " , src - > fb_address , dst - > fb_address ) ;
2014-09-13 20:08:29 -07:00
}
2013-11-15 14:24:25 +01:00
}
2013-08-17 11:23:51 +02:00
2018-02-08 12:02:44 +01:00
void ConvertFromBGRA8888 ( u8 * dst , u8 * src , u32 dstStride , u32 srcStride , u32 width , u32 height , GEBufferFormat format ) {
2014-09-13 16:37:59 -07:00
// 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 ) {
2018-06-03 07:45:48 -07:00
ConvertFromBGRA8888 ( dst , src , dstStride , srcStride , width , height , Draw : : DataFormat : : R8G8B8A8_UNORM ) ;
2014-09-13 16:37:59 -07:00
} else {
// But here it shouldn't matter if they do intersect
2013-11-15 14:24:25 +01:00
u16 * dst16 = ( u16 * ) dst ;
switch ( format ) {
case GE_FORMAT_565 : // BGR 565
2014-09-13 16:37:59 -07:00
for ( u32 y = 0 ; y < height ; + + y ) {
2015-04-08 19:59:12 +02:00
ConvertBGRA8888ToRGB565 ( dst16 , src32 , width ) ;
2014-09-13 16:37:59 -07:00
src32 + = srcStride ;
dst16 + = dstStride ;
2013-11-15 14:24:25 +01:00
}
break ;
case GE_FORMAT_5551 : // ABGR 1555
2014-09-13 16:37:59 -07:00
for ( u32 y = 0 ; y < height ; + + y ) {
ConvertBGRA8888ToRGBA5551 ( dst16 , src32 , width ) ;
src32 + = srcStride ;
dst16 + = dstStride ;
2013-11-15 14:24:25 +01:00
}
break ;
case GE_FORMAT_4444 : // ABGR 4444
2014-09-13 16:37:59 -07:00
for ( u32 y = 0 ; y < height ; + + y ) {
2015-04-08 19:59:12 +02:00
ConvertBGRA8888ToRGBA4444 ( dst16 , src32 , width ) ;
2014-09-13 16:37:59 -07:00
src32 + = srcStride ;
dst16 + = dstStride ;
2013-11-15 14:24:25 +01:00
}
break ;
case GE_FORMAT_8888 :
2014-09-13 16:37:59 -07:00
case GE_FORMAT_INVALID :
2013-11-15 14:24:25 +01:00
// Not possible.
break ;
2013-08-20 18:46:57 +02:00
}
2013-08-17 11:23:51 +02:00
}
}
2017-10-18 11:20:58 +02:00
void FramebufferManagerDX9 : : PackFramebufferSync_ ( VirtualFramebuffer * vfb , int x , int y , int w , int h ) {
2014-09-13 16:37:59 -07:00
if ( ! vfb - > fbo ) {
ERROR_LOG_REPORT_ONCE ( vfbfbozero , SCEGE , " PackFramebufferDirectx9_: vfb->fbo == 0 " ) ;
2013-11-15 15:15:12 +01:00
return ;
}
2018-11-11 10:54:28 +01:00
const u32 fb_address = vfb - > fb_address & 0x3FFFFFFF ;
2014-09-13 16:37:59 -07:00
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 ) ;
2014-09-13 16:37:59 -07:00
2017-02-06 11:26:24 +01:00
LPDIRECT3DSURFACE9 renderTarget = ( LPDIRECT3DSURFACE9 ) draw_ - > GetFramebufferAPITexture ( vfb - > fbo , Draw : : FB_COLOR_BIT | Draw : : FB_SURFACE_BIT , 0 ) ;
2014-09-13 16:37:59 -07:00
D3DSURFACE_DESC desc ;
renderTarget - > GetDesc ( & desc ) ;
2015-06-21 12:50:02 -07:00
LPDIRECT3DSURFACE9 offscreen = GetOffscreenSurface ( renderTarget , vfb ) ;
2014-09-13 22:28:39 -07:00
if ( offscreen ) {
2017-03-02 11:39:02 +01:00
HRESULT hr = device_ - > GetRenderTargetData ( renderTarget , offscreen ) ;
2014-09-13 16:37:59 -07:00
if ( SUCCEEDED ( hr ) ) {
D3DLOCKED_RECT locked ;
2014-09-13 17:14:29 -07:00
u32 widthFactor = vfb - > renderWidth / vfb - > bufferWidth ;
u32 heightFactor = vfb - > renderHeight / vfb - > bufferHeight ;
2015-09-17 22:02:15 +02:00
RECT rect = { ( LONG ) ( x * widthFactor ) , ( LONG ) ( y * heightFactor ) , ( LONG ) ( ( x + w ) * widthFactor ) , ( LONG ) ( ( y + h ) * heightFactor ) } ;
2014-09-13 16:37:59 -07:00
hr = offscreen - > LockRect ( & locked , & rect , D3DLOCK_READONLY ) ;
if ( SUCCEEDED ( hr ) ) {
// TODO: Handle the other formats? We don't currently create them, I think.
2014-09-13 17:14:29 -07:00
const int dstByteOffset = ( y * vfb - > fb_stride + x ) * dstBpp ;
2014-09-13 16:37:59 -07:00
// Pixel size always 4 here because we always request BGRA8888.
2018-02-08 12:02:44 +01:00
ConvertFromBGRA8888 ( Memory : : GetPointer ( fb_address + dstByteOffset ) , ( u8 * ) locked . pBits , vfb - > fb_stride , locked . Pitch / 4 , w , h , vfb - > format ) ;
2014-09-13 16:37:59 -07:00
offscreen - > UnlockRect ( ) ;
2014-09-13 19:21:59 -07:00
} else {
ERROR_LOG_REPORT ( G3D , " Unable to lock rect from %08x: %d,%d %dx%d of %dx%d " , fb_address , rect . left , rect . top , rect . right , rect . bottom , vfb - > renderWidth , vfb - > renderHeight ) ;
2014-09-13 16:37:59 -07:00
}
2014-09-13 19:21:59 -07:00
} else {
ERROR_LOG_REPORT ( G3D , " Unable to download render target data from %08x " , fb_address ) ;
2013-11-15 14:24:25 +01:00
}
2013-08-17 11:23:51 +02:00
}
}
2014-09-13 22:28:39 -07:00
2016-01-18 12:57:37 -08:00
void FramebufferManagerDX9 : : 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 ;
}
// We always read the depth buffer in 24_8 format.
2018-11-11 10:54:28 +01:00
const u32 z_address = vfb - > z_address ;
2016-01-18 12:57:37 -08:00
2017-03-13 12:32:21 +01:00
DEBUG_LOG ( FRAMEBUF , " Reading depthbuffer to mem at %08x for vfb=%08x " , z_address , vfb - > fb_address ) ;
2016-01-18 12:57:37 -08:00
2017-02-06 11:26:24 +01:00
LPDIRECT3DTEXTURE9 tex = ( LPDIRECT3DTEXTURE9 ) draw_ - > GetFramebufferAPITexture ( vfb - > fbo , Draw : : FB_DEPTH_BIT , 0 ) ;
2016-01-18 12:57:37 -08:00
if ( tex ) {
D3DSURFACE_DESC desc ;
D3DLOCKED_RECT locked ;
tex - > GetLevelDesc ( 0 , & desc ) ;
RECT rect = { 0 , 0 , ( LONG ) desc . Width , ( LONG ) desc . Height } ;
HRESULT hr = tex - > LockRect ( 0 , & locked , & rect , D3DLOCK_READONLY ) ;
if ( SUCCEEDED ( hr ) ) {
const int dstByteOffset = y * vfb - > fb_stride * sizeof ( s16 ) ;
const u32 * packed = ( const u32 * ) locked . pBits ;
u16 * depth = ( u16 * ) Memory : : GetPointer ( z_address ) ;
// TODO: Optimize.
for ( int yp = 0 ; yp < h ; + + yp ) {
for ( int xp = 0 ; xp < w ; + + xp ) {
2017-02-12 17:50:37 +01:00
const int offset = ( yp + y ) * vfb - > z_stride + x + xp ;
2016-01-18 12:57:37 -08:00
float scaled = FromScaledDepth ( ( packed [ offset ] & 0x00FFFFFF ) * ( 1.0f / 16777215.0f ) ) ;
if ( scaled < = 0.0f ) {
depth [ offset ] = 0 ;
} else if ( scaled > = 65535.0f ) {
depth [ offset ] = 65535 ;
} else {
depth [ offset ] = ( int ) scaled ;
}
}
}
tex - > UnlockRect ( 0 ) ;
} else {
ERROR_LOG_REPORT ( G3D , " Unable to lock rect from depth %08x: %d,%d %dx%d of %dx%d " , vfb - > fb_address , rect . left , rect . top , rect . right , rect . bottom , vfb - > renderWidth , vfb - > renderHeight ) ;
}
} else {
ERROR_LOG_REPORT ( G3D , " Unable to download render target depth from %08x " , vfb - > fb_address ) ;
}
}
2013-11-15 14:24:25 +01:00
void FramebufferManagerDX9 : : EndFrame ( ) {
}
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
void FramebufferManagerDX9 : : DeviceLost ( ) {
2017-04-13 23:07:21 -07:00
DestroyAllFBOs ( ) ;
2013-11-15 14:24:25 +01:00
}
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
void FramebufferManagerDX9 : : DecimateFBOs ( ) {
2017-02-07 00:42:39 +01:00
FramebufferManagerCommon : : DecimateFBOs ( ) ;
2014-09-13 22:28:39 -07:00
for ( auto it = offscreenSurfaces_ . begin ( ) ; it ! = offscreenSurfaces_ . end ( ) ; ) {
int age = frameLastFramebufUsed_ - it - > second . last_frame_used ;
if ( age > FBO_OLD_AGE ) {
it - > second . surface - > Release ( ) ;
2018-06-03 07:45:21 -07:00
it = offscreenSurfaces_ . erase ( it ) ;
2014-09-13 22:28:39 -07:00
} else {
+ + it ;
}
}
2013-08-17 11:23:51 +02:00
}
2017-04-13 23:07:21 -07:00
void FramebufferManagerDX9 : : DestroyAllFBOs ( ) {
2013-08-17 11:23:51 +02:00
currentRenderVfb_ = 0 ;
2013-11-15 14:24:25 +01:00
displayFramebuf_ = 0 ;
prevDisplayFramebuf_ = 0 ;
prevPrevDisplayFramebuf_ = 0 ;
2013-08-17 11:23:51 +02:00
for ( size_t i = 0 ; i < vfbs_ . size ( ) ; + + i ) {
2014-09-09 08:12:42 -07:00
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 ) ;
2013-11-15 14:24:25 +01:00
DestroyFramebuf ( vfb ) ;
}
vfbs_ . clear ( ) ;
2014-09-13 22:28:39 -07:00
for ( size_t i = 0 ; i < bvfbs_ . size ( ) ; + + i ) {
VirtualFramebuffer * vfb = bvfbs_ [ i ] ;
DestroyFramebuf ( vfb ) ;
}
bvfbs_ . clear ( ) ;
2018-06-03 07:45:21 -07:00
for ( auto & it : offscreenSurfaces_ ) {
it . second . surface - > Release ( ) ;
2014-09-13 22:28:39 -07:00
}
offscreenSurfaces_ . clear ( ) ;
2017-12-01 12:15:55 +01:00
SetNumExtraFBOs ( 0 ) ;
2013-11-15 14:24:25 +01:00
}
void FramebufferManagerDX9 : : Resized ( ) {
2017-04-24 11:58:16 -07:00
FramebufferManagerCommon : : Resized ( ) ;
if ( UpdateSize ( ) ) {
DestroyAllFBOs ( ) ;
}
2013-08-17 11:23:51 +02:00
}
2017-02-14 12:42:35 +01:00
bool FramebufferManagerDX9 : : GetFramebuffer ( u32 fb_address , int fb_stride , GEBufferFormat fb_format , GPUDebugBuffer & buffer , int maxRes ) {
2014-09-09 08:12:42 -07:00
VirtualFramebuffer * vfb = currentRenderVfb_ ;
2014-08-24 21:23:23 -07:00
if ( ! vfb ) {
vfb = GetVFBAt ( fb_address ) ;
}
if ( ! vfb ) {
// If there's no vfb and we're drawing there, must be memory?
2018-11-11 10:54:28 +01:00
buffer = GPUDebugBuffer ( Memory : : GetPointer ( fb_address ) , fb_stride , 512 , fb_format ) ;
2014-08-24 21:23:23 -07:00
return true ;
}
2017-02-06 11:26:24 +01:00
LPDIRECT3DSURFACE9 renderTarget = vfb - > fbo ? ( LPDIRECT3DSURFACE9 ) draw_ - > GetFramebufferAPITexture ( vfb - > fbo , Draw : : FB_COLOR_BIT | Draw : : FB_SURFACE_BIT , 0 ) : nullptr ;
2014-12-20 08:31:56 -08:00
bool success = false ;
if ( renderTarget ) {
2017-02-04 18:46:12 +01:00
Draw : : Framebuffer * tempFBO = nullptr ;
2016-06-12 07:09:01 -07:00
int w = vfb - > renderWidth , h = vfb - > renderHeight ;
if ( maxRes > 0 & & vfb - > renderWidth > vfb - > width * maxRes ) {
// Let's resize. We must stretch to a render target first.
w = vfb - > width * maxRes ;
h = vfb - > height * maxRes ;
2017-02-06 11:26:24 +01:00
tempFBO = draw_ - > CreateFramebuffer ( { w , h , 1 , 1 , false , Draw : : FBO_8888 } ) ;
if ( draw_ - > BlitFramebuffer ( vfb - > fbo , 0 , 0 , vfb - > renderWidth , vfb - > renderHeight , tempFBO , 0 , 0 , w , h , Draw : : FB_COLOR_BIT , g_Config . iBufFilter = = SCALE_LINEAR ? Draw : : FB_BLIT_LINEAR : Draw : : FB_BLIT_NEAREST ) ) {
renderTarget = ( LPDIRECT3DSURFACE9 ) draw_ - > GetFramebufferAPITexture ( tempFBO , Draw : : FB_COLOR_BIT | Draw : : FB_SURFACE_BIT , 0 ) ;
2016-06-12 07:09:01 -07:00
}
}
2015-06-21 12:50:02 -07:00
LPDIRECT3DSURFACE9 offscreen = GetOffscreenSurface ( renderTarget , vfb ) ;
2014-12-20 08:31:56 -08:00
if ( offscreen ) {
2016-06-12 07:09:01 -07:00
success = GetRenderTargetFramebuffer ( renderTarget , offscreen , w , h , buffer ) ;
}
2014-12-20 08:31:56 -08:00
}
2014-08-24 21:23:23 -07:00
2014-12-20 08:31:56 -08:00
return success ;
}
2014-08-24 21:23:23 -07:00
2016-09-25 16:35:43 -07:00
bool FramebufferManagerDX9 : : GetOutputFramebuffer ( GPUDebugBuffer & buffer ) {
2014-12-20 08:31:56 -08:00
LPDIRECT3DSURFACE9 renderTarget = nullptr ;
2017-03-02 11:39:02 +01:00
HRESULT hr = device_ - > GetRenderTarget ( 0 , & renderTarget ) ;
2014-12-20 08:31:56 -08:00
bool success = false ;
if ( renderTarget & & SUCCEEDED ( hr ) ) {
D3DSURFACE_DESC desc ;
renderTarget - > GetDesc ( & desc ) ;
LPDIRECT3DSURFACE9 offscreen = nullptr ;
2017-03-02 11:39:02 +01:00
HRESULT hr = device_ - > CreateOffscreenPlainSurface ( desc . Width , desc . Height , desc . Format , D3DPOOL_SYSTEMMEM , & offscreen , NULL ) ;
2014-12-20 08:31:56 -08:00
if ( offscreen & & SUCCEEDED ( hr ) ) {
success = GetRenderTargetFramebuffer ( renderTarget , offscreen , PSP_CoreParameter ( ) . pixelWidth , PSP_CoreParameter ( ) . pixelHeight , buffer ) ;
offscreen - > Release ( ) ;
}
2014-09-11 23:52:06 -07:00
renderTarget - > Release ( ) ;
}
2014-12-20 08:31:56 -08:00
return success ;
}
bool FramebufferManagerDX9 : : GetRenderTargetFramebuffer ( LPDIRECT3DSURFACE9 renderTarget , LPDIRECT3DSURFACE9 offscreen , int w , int h , GPUDebugBuffer & buffer ) {
D3DSURFACE_DESC desc ;
renderTarget - > GetDesc ( & desc ) ;
2014-08-24 21:23:23 -07:00
bool success = false ;
2017-03-02 11:39:02 +01:00
HRESULT hr = device_ - > GetRenderTargetData ( renderTarget , offscreen ) ;
2014-08-24 21:23:23 -07:00
if ( SUCCEEDED ( hr ) ) {
D3DLOCKED_RECT locked ;
2014-12-20 08:31:56 -08:00
RECT rect = { 0 , 0 , w , h } ;
2014-08-24 21:23:23 -07:00
hr = offscreen - > LockRect ( & locked , & rect , D3DLOCK_READONLY ) ;
if ( SUCCEEDED ( hr ) ) {
2014-08-24 22:08:28 -07:00
// TODO: Handle the other formats? We don't currently create them, I think.
2014-09-09 01:42:21 -07:00
buffer . Allocate ( locked . Pitch / 4 , desc . Height , GPU_DBG_FORMAT_8888_BGRA , false ) ;
memcpy ( buffer . GetData ( ) , locked . pBits , locked . Pitch * desc . Height ) ;
2014-08-24 21:23:23 -07:00
offscreen - > UnlockRect ( ) ;
success = true ;
}
}
return success ;
2013-11-15 14:24:25 +01:00
}
2017-02-14 12:42:35 +01:00
bool FramebufferManagerDX9 : : GetDepthbuffer ( u32 fb_address , int fb_stride , u32 z_address , int z_stride , GPUDebugBuffer & buffer ) {
2014-09-14 11:14:56 -07: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?
2018-11-11 10:54:28 +01:00
buffer = GPUDebugBuffer ( Memory : : GetPointer ( z_address ) , z_stride , 512 , GPU_DBG_FORMAT_16BIT ) ;
2014-09-14 11:14:56 -07:00
return true ;
}
bool success = false ;
2017-02-06 11:26:24 +01:00
LPDIRECT3DTEXTURE9 tex = ( LPDIRECT3DTEXTURE9 ) draw_ - > GetFramebufferAPITexture ( vfb - > fbo , Draw : : FB_DEPTH_BIT , 0 ) ;
2014-09-14 11:14:56 -07:00
if ( tex ) {
D3DSURFACE_DESC desc ;
D3DLOCKED_RECT locked ;
tex - > GetLevelDesc ( 0 , & desc ) ;
2015-09-17 22:02:15 +02:00
RECT rect = { 0 , 0 , ( LONG ) desc . Width , ( LONG ) desc . Height } ;
2014-09-14 11:14:56 -07:00
HRESULT hr = tex - > LockRect ( 0 , & locked , & rect , D3DLOCK_READONLY ) ;
if ( SUCCEEDED ( hr ) ) {
GPUDebugBufferFormat fmt = GPU_DBG_FORMAT_24BIT_8X ;
2016-01-18 01:30:05 -08:00
if ( gstate_c . Supports ( GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT ) ) {
fmt = GPU_DBG_FORMAT_24BIT_8X_DIV_256 ;
}
2014-09-14 11:14:56 -07:00
int pixelSize = 4 ;
2015-10-31 23:59:23 +01:00
buffer . Allocate ( locked . Pitch / pixelSize , desc . Height , fmt , false ) ;
2014-09-14 11:14:56 -07:00
memcpy ( buffer . GetData ( ) , locked . pBits , locked . Pitch * desc . Height ) ;
success = true ;
tex - > UnlockRect ( 0 ) ;
}
}
return success ;
2013-11-15 14:24:25 +01:00
}
2017-02-14 12:42:35 +01:00
bool FramebufferManagerDX9 : : GetStencilbuffer ( u32 fb_address , int fb_stride , GPUDebugBuffer & buffer ) {
2014-09-14 11:14:56 -07: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?
2018-11-11 10:54:28 +01:00
buffer = GPUDebugBuffer ( Memory : : GetPointer ( vfb - > z_address ) , vfb - > z_stride , 512 , GPU_DBG_FORMAT_16BIT ) ;
2014-09-14 11:14:56 -07:00
return true ;
}
bool success = false ;
2017-02-06 11:26:24 +01:00
LPDIRECT3DTEXTURE9 tex = ( LPDIRECT3DTEXTURE9 ) draw_ - > GetFramebufferAPITexture ( vfb - > fbo , Draw : : FB_DEPTH_BIT , 0 ) ;
2014-09-14 11:14:56 -07:00
if ( tex ) {
D3DSURFACE_DESC desc ;
D3DLOCKED_RECT locked ;
tex - > GetLevelDesc ( 0 , & desc ) ;
2015-09-17 22:02:15 +02:00
RECT rect = { 0 , 0 , ( LONG ) desc . Width , ( LONG ) desc . Height } ;
2014-09-14 11:14:56 -07:00
HRESULT hr = tex - > LockRect ( 0 , & locked , & rect , D3DLOCK_READONLY ) ;
if ( SUCCEEDED ( hr ) ) {
GPUDebugBufferFormat fmt = GPU_DBG_FORMAT_24X_8BIT ;
int pixelSize = 4 ;
2015-10-31 23:59:23 +01:00
buffer . Allocate ( locked . Pitch / pixelSize , desc . Height , fmt , false ) ;
2014-09-14 11:14:56 -07:00
memcpy ( buffer . GetData ( ) , locked . pBits , locked . Pitch * desc . Height ) ;
success = true ;
tex - > UnlockRect ( 0 ) ;
}
}
return success ;
2013-11-15 14:24:25 +01:00
}
} // namespace DX9