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"
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"
# 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
# include "helper/dx_state.h"
2015-09-06 13:05:18 +02:00
# include "helper/dx_fbo.h"
2013-08-17 11:23:51 +02:00
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"
# include "GPU/Directx9/TransformPipelineDX9.h"
2013-08-17 11:23:51 +02:00
2013-09-17 00:48:14 -04:00
# include <algorithm>
2015-09-23 12:25:38 +02:00
void ShowScreenResolution ( ) ;
2013-09-15 08:53:21 -07:00
namespace DX9 {
2014-09-13 16:37:59 -07:00
static void ConvertFromRGBA8888 ( u8 * dst , u8 * src , u32 dstStride , u32 srcStride , u32 width , u32 height , GEBufferFormat format ) ;
2013-08-17 11:23:51 +02:00
2015-11-03 22:37:19 -08:00
void FramebufferManagerDX9 : : ClearBuffer ( bool keepState ) {
if ( keepState ) {
dxstate . scissorTest . force ( false ) ;
dxstate . depthWrite . force ( TRUE ) ;
dxstate . colorMask . force ( true , true , true , true ) ;
dxstate . stencilFunc . force ( D3DCMP_ALWAYS , 0 , 0 ) ;
dxstate . stencilMask . force ( 0xFF ) ;
} else {
dxstate . scissorTest . disable ( ) ;
dxstate . depthWrite . set ( TRUE ) ;
dxstate . colorMask . set ( true , true , true , true ) ;
dxstate . stencilFunc . set ( D3DCMP_ALWAYS , 0 , 0 ) ;
dxstate . stencilMask . set ( 0xFF ) ;
}
2015-02-26 08:40:24 -08:00
pD3Ddevice - > Clear ( 0 , NULL , D3DCLEAR_STENCIL | D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_ARGB ( 0 , 0 , 0 , 0 ) , 0 , 0 ) ;
2015-11-03 22:37:19 -08:00
if ( keepState ) {
dxstate . scissorTest . restore ( ) ;
dxstate . depthWrite . restore ( ) ;
dxstate . colorMask . restore ( ) ;
dxstate . stencilFunc . restore ( ) ;
dxstate . stencilMask . restore ( ) ;
}
2013-11-15 14:24:25 +01:00
}
2013-08-17 11:23:51 +02:00
2014-09-09 08:12:42 -07:00
void FramebufferManagerDX9 : : ClearDepthBuffer ( ) {
dxstate . scissorTest . disable ( ) ;
dxstate . depthWrite . set ( TRUE ) ;
dxstate . colorMask . set ( false , false , false , false ) ;
dxstate . stencilFunc . set ( D3DCMP_NEVER , 0 , 0 ) ;
2015-02-26 08:40:24 -08:00
pD3Ddevice - > Clear ( 0 , NULL , D3DCLEAR_ZBUFFER , D3DCOLOR_ARGB ( 0 , 0 , 0 , 0 ) , 0 , 0 ) ;
2014-09-09 08:12:42 -07:00
}
void FramebufferManagerDX9 : : DisableState ( ) {
2013-11-15 14:24:25 +01:00
dxstate . blend . disable ( ) ;
dxstate . cullMode . set ( false , false ) ;
dxstate . depthTest . disable ( ) ;
dxstate . scissorTest . disable ( ) ;
dxstate . stencilTest . disable ( ) ;
2014-08-30 11:18:18 -07:00
dxstate . colorMask . set ( true , true , true , true ) ;
dxstate . stencilMask . set ( 0xFF ) ;
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
FramebufferManagerDX9 : : FramebufferManagerDX9 ( ) :
drawPixelsTex_ ( 0 ) ,
2014-09-13 15:09:30 -07:00
convBuf ( 0 ) ,
2014-09-14 02:21:41 -07:00
stencilUploadPS_ ( nullptr ) ,
stencilUploadVS_ ( nullptr ) ,
stencilUploadFailed_ ( false ) ,
2014-09-13 19:56:08 -07:00
gameUsesSequentialCopies_ ( false ) {
2013-11-15 14:24:25 +01:00
}
FramebufferManagerDX9 : : ~ FramebufferManagerDX9 ( ) {
2014-09-13 19:56:08 -07:00
if ( drawPixelsTex_ ) {
2013-11-15 14:24:25 +01:00
drawPixelsTex_ - > Release ( ) ;
}
2014-09-13 22:39:54 -07:00
for ( auto it = tempFBOs_ . begin ( ) , end = tempFBOs_ . end ( ) ; it ! = end ; + + it ) {
fbo_destroy ( it - > second . fbo ) ;
}
2014-09-13 22:28:39 -07:00
for ( auto it = offscreenSurfaces_ . begin ( ) , end = offscreenSurfaces_ . end ( ) ; it ! = end ; + + it ) {
it - > second . surface - > Release ( ) ;
}
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 ( ) ;
}
2013-11-15 14:24:25 +01:00
}
2014-09-13 13:09:26 -07:00
void FramebufferManagerDX9 : : MakePixelTexture ( const u8 * srcPixels , GEBufferFormat srcPixelFormat , int srcStride , int width , int height ) {
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 ;
if ( pD3DdeviceEx ) {
pool = D3DPOOL_DEFAULT ;
usage = D3DUSAGE_DYNAMIC ;
}
HRESULT hr = pD3Ddevice - > CreateTexture ( width , height , 1 , usage , D3DFMT ( D3DFMT_A8R8G8B8 ) , pool , & drawPixelsTex_ , NULL ) ;
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 ;
}
2014-09-01 08:20:27 -07:00
drawPixelsTex_ - > LockRect ( 0 , & rect , NULL , 0 ) ;
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 ) ;
2015-01-22 19:53:32 +01:00
// D3DXSaveTextureToFile("game:\\cc.png", D3DXIFF_PNG, drawPixelsTex_, NULL);
2014-09-13 13:09:26 -07:00
}
void FramebufferManagerDX9 : : DrawPixels ( VirtualFramebuffer * vfb , int dstX , int dstY , const u8 * srcPixels , GEBufferFormat srcPixelFormat , int srcStride , int width , int height ) {
2015-11-14 13:24:51 +01:00
if ( useBufferedRendering_ & & vfb & & vfb - > fbo_dx9 ) {
fbo_bind_as_render_target ( vfb - > fbo_dx9 ) ;
2015-11-12 14:47:43 +01:00
DXSetViewport ( 0 , 0 , vfb - > renderWidth , vfb - > renderHeight ) ;
2015-10-31 21:07:53 +01:00
} else {
float x , y , w , h ;
2015-11-03 00:24:19 +01:00
CenterDisplayOutputRect ( & x , & y , & w , & h , 480.0f , 272.0f , ( float ) pixelWidth_ , ( float ) pixelHeight_ , ROTATION_LOCKED_HORIZONTAL ) ;
2015-11-12 14:47:43 +01:00
DXSetViewport ( x , y , w , h ) ;
2014-09-13 13:09:26 -07:00
}
MakePixelTexture ( srcPixels , srcPixelFormat , srcStride , width , height ) ;
DisableState ( ) ;
2015-11-01 13:32:03 +01:00
DrawActiveTexture ( drawPixelsTex_ , dstX , dstY , width , height , vfb - > bufferWidth , vfb - > bufferHeight , 0.0f , 0.0f , 1.0f , 1.0f , ROTATION_LOCKED_HORIZONTAL ) ;
2014-09-13 14:57:45 -07:00
textureCache_ - > ForgetLastTexture ( ) ;
2015-11-12 14:47:43 +01:00
dxstate . viewport . restore ( ) ;
2014-09-13 13:09:26 -07:00
}
2015-11-01 15:34:53 +01:00
void FramebufferManagerDX9 : : DrawFramebufferToOutput ( const u8 * srcPixels , GEBufferFormat srcPixelFormat , int srcStride , bool applyPostShader ) {
2014-09-13 13:09:26 -07:00
MakePixelTexture ( srcPixels , srcPixelFormat , srcStride , 512 , 272 ) ;
2013-11-15 14:24:25 +01:00
2014-09-13 13:09:26 -07:00
DisableState ( ) ;
// This might draw directly at the backbuffer (if so, applyPostShader is set) so if there's a post shader, we need to apply it here.
// Should try to unify this path with the regular path somehow, but this simple solution works for most of the post shaders
// (it always runs at output resolution so FXAA may look odd).
2013-11-15 14:24:25 +01:00
float x , y , w , h ;
2015-05-12 22:44:02 +02:00
int uvRotation = ( g_Config . iRenderingMode ! = FB_NON_BUFFERED_MODE ) ? g_Config . iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL ;
2015-11-18 12:25:54 +01:00
CenterDisplayOutputRect ( & x , & y , & w , & h , 480.0f , 272.0f , ( float ) pixelWidth_ , ( float ) pixelHeight_ , uvRotation ) ;
DrawActiveTexture ( drawPixelsTex_ , x , y , w , h , ( float ) pixelWidth_ , ( float ) pixelHeight_ , 0.0f , 0.0f , 480.0f / 512.0f , 1.0f , uvRotation ) ;
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
2015-11-01 13:32:03 +01:00
void FramebufferManagerDX9 : : DrawActiveTexture ( LPDIRECT3DTEXTURE9 tex , float x , float y , float w , float h , float destW , float destH , float u0 , float v0 , float u1 , float v1 , int uvRotation ) {
2014-09-13 13:09:26 -07:00
// TODO: StretchRect instead?
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
}
pD3Ddevice - > SetRenderState ( D3DRS_CULLMODE , D3DCULL_NONE ) ;
pD3Ddevice - > SetVertexDeclaration ( pFramebufferVertexDecl ) ;
pD3Ddevice - > SetPixelShader ( pFramebufferPixelShader ) ;
pD3Ddevice - > SetVertexShader ( pFramebufferVertexShader ) ;
2014-09-13 20:05:41 -07:00
shaderManager_ - > DirtyLastShader ( ) ;
2013-11-15 14:24:25 +01:00
if ( tex ! = NULL ) {
pD3Ddevice - > SetTexture ( 0 , tex ) ;
}
2014-09-13 19:21:59 -07:00
HRESULT hr = pD3Ddevice - > DrawPrimitiveUP ( D3DPT_TRIANGLEFAN , 2 , coord , 5 * sizeof ( float ) ) ;
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
2014-09-09 08:12:42 -07:00
void FramebufferManagerDX9 : : DestroyFramebuf ( VirtualFramebuffer * v ) {
2013-11-15 14:24:25 +01:00
textureCache_ - > NotifyFramebuffer ( v - > fb_address , v , NOTIFY_FB_DESTROYED ) ;
2015-11-14 13:24:51 +01:00
if ( v - > fbo_dx9 ) {
fbo_destroy ( v - > fbo_dx9 ) ;
v - > fbo_dx9 = 0 ;
2013-11-15 14:24:25 +01:00
}
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
// Wipe some pointers
if ( currentRenderVfb_ = = v )
currentRenderVfb_ = 0 ;
if ( displayFramebuf_ = = v )
displayFramebuf_ = 0 ;
if ( prevDisplayFramebuf_ = = v )
prevDisplayFramebuf_ = 0 ;
if ( prevPrevDisplayFramebuf_ = = v )
prevPrevDisplayFramebuf_ = 0 ;
delete v ;
}
2013-08-17 11:23:51 +02:00
2014-09-13 14:26:39 -07:00
void FramebufferManagerDX9 : : RebindFramebuffer ( ) {
2015-11-14 13:24:51 +01:00
if ( currentRenderVfb_ & & currentRenderVfb_ - > fbo_dx9 ) {
fbo_bind_as_render_target ( currentRenderVfb_ - > fbo_dx9 ) ;
2014-09-13 14:26:39 -07:00
} else {
fbo_unbind ( ) ;
}
}
2014-09-09 22:56:54 -07:00
void FramebufferManagerDX9 : : ResizeFramebufFBO ( VirtualFramebuffer * vfb , u16 w , u16 h , bool force ) {
VirtualFramebuffer old = * vfb ;
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
if ( force ) {
vfb - > bufferWidth = w ;
vfb - > bufferHeight = h ;
} else {
if ( vfb - > bufferWidth > = w & & vfb - > bufferHeight > = h ) {
return ;
}
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
// In case it gets thin and wide, don't resize down either side.
vfb - > bufferWidth = std : : max ( vfb - > bufferWidth , w ) ;
vfb - > bufferHeight = std : : max ( vfb - > bufferHeight , h ) ;
}
2013-08-17 11:23:51 +02:00
2015-01-23 10:40:49 +01:00
SetRenderSize ( vfb ) ;
2013-08-20 18:46:57 +02:00
2014-09-09 22:56:54 -07:00
bool trueColor = g_Config . bTrueColor ;
if ( hackForce04154000Download_ & & vfb - > fb_address = = 0x00154000 ) {
trueColor = true ;
}
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
if ( trueColor ) {
vfb - > colorDepth = FBO_8888 ;
} else {
switch ( vfb - > format ) {
case GE_FORMAT_4444 :
vfb - > colorDepth = FBO_4444 ;
break ;
case GE_FORMAT_5551 :
vfb - > colorDepth = FBO_5551 ;
break ;
case GE_FORMAT_565 :
vfb - > colorDepth = FBO_565 ;
break ;
case GE_FORMAT_8888 :
default :
vfb - > colorDepth = FBO_8888 ;
break ;
2013-11-15 14:24:25 +01:00
}
}
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
textureCache_ - > ForgetLastTexture ( ) ;
fbo_unbind ( ) ;
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
if ( ! useBufferedRendering_ ) {
2015-11-14 13:24:51 +01:00
if ( vfb - > fbo_dx9 ) {
fbo_destroy ( vfb - > fbo_dx9 ) ;
vfb - > fbo_dx9 = 0 ;
2013-08-17 11:23:51 +02:00
}
2014-09-09 22:56:54 -07:00
return ;
}
2013-08-17 11:23:51 +02:00
2015-11-14 13:24:51 +01:00
vfb - > fbo_dx9 = fbo_create ( vfb - > renderWidth , vfb - > renderHeight , 1 , true , ( FBOColorDepth ) vfb - > colorDepth ) ;
if ( old . fbo_dx9 ) {
2014-09-09 22:56:54 -07:00
INFO_LOG ( SCEGE , " Resizing FBO for %08x : %i x %i x %i " , vfb - > fb_address , w , h , vfb - > format ) ;
if ( vfb - > fbo ) {
2015-11-14 13:24:51 +01:00
fbo_bind_as_render_target ( vfb - > fbo_dx9 ) ;
2014-09-09 22:56:54 -07:00
ClearBuffer ( ) ;
if ( ! g_Config . bDisableSlowFramebufEffects ) {
2014-09-13 15:12:06 -07:00
BlitFramebuffer ( vfb , 0 , 0 , & old , 0 , 0 , std : : min ( vfb - > bufferWidth , vfb - > width ) , std : : min ( vfb - > height , vfb - > bufferHeight ) , 0 ) ;
2013-11-15 14:24:25 +01:00
}
2013-08-17 11:23:51 +02:00
}
2015-11-14 13:24:51 +01:00
fbo_destroy ( old . fbo_dx9 ) ;
if ( vfb - > fbo_dx9 ) {
fbo_bind_as_render_target ( vfb - > fbo_dx9 ) ;
2014-09-09 22:56:54 -07:00
}
}
2013-08-20 18:46:57 +02:00
2014-09-09 22:56:54 -07:00
if ( ! vfb - > fbo ) {
ERROR_LOG ( SCEGE , " Error creating FBO! %i x %i " , vfb - > renderWidth , vfb - > renderHeight ) ;
}
}
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
void FramebufferManagerDX9 : : NotifyRenderFramebufferCreated ( VirtualFramebuffer * vfb ) {
if ( ! useBufferedRendering_ ) {
fbo_unbind ( ) ;
// Let's ignore rendering to targets that have not (yet) been displayed.
gstate_c . skipDrawReason | = SKIPDRAW_NON_DISPLAYED_FB ;
}
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
textureCache_ - > NotifyFramebuffer ( vfb - > fb_address , vfb , NOTIFY_FB_CREATED ) ;
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
ClearBuffer ( ) ;
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
// ugly...
if ( gstate_c . curRTWidth ! = vfb - > width | | gstate_c . curRTHeight ! = vfb - > height ) {
shaderManager_ - > DirtyUniform ( DIRTY_PROJTHROUGHMATRIX ) ;
}
2014-09-13 22:01:32 -07:00
if ( gstate_c . curRTRenderWidth ! = vfb - > renderWidth | | gstate_c . curRTRenderHeight ! = vfb - > renderHeight ) {
shaderManager_ - > DirtyUniform ( DIRTY_PROJMATRIX ) ;
shaderManager_ - > DirtyUniform ( DIRTY_PROJTHROUGHMATRIX ) ;
}
2014-09-09 22:56:54 -07:00
}
2015-08-05 01:03:49 +02:00
void FramebufferManagerDX9 : : NotifyRenderFramebufferSwitched ( VirtualFramebuffer * prevVfb , VirtualFramebuffer * vfb , bool isClearingDepth ) {
2014-09-09 22:56:54 -07:00
if ( ShouldDownloadFramebuffer ( vfb ) & & ! vfb - > memoryUpdated ) {
2014-09-13 15:09:30 -07:00
ReadFramebufferToMemory ( vfb , true , 0 , 0 , vfb - > width , vfb - > height ) ;
2014-09-09 22:56:54 -07:00
}
textureCache_ - > ForgetLastTexture ( ) ;
if ( useBufferedRendering_ ) {
2015-11-14 13:24:51 +01:00
if ( vfb - > fbo_dx9 ) {
fbo_bind_as_render_target ( vfb - > fbo_dx9 ) ;
2013-08-17 11:23:51 +02:00
} else {
2014-09-09 22:56:54 -07:00
// wtf? This should only happen very briefly when toggling bBufferedRendering
2013-08-17 11:23:51 +02:00
fbo_unbind ( ) ;
2014-09-09 22:56:54 -07:00
}
} else {
2015-11-14 13:24:51 +01:00
if ( vfb - > fbo_dx9 ) {
2014-09-09 22:56:54 -07:00
// wtf? This should only happen very briefly when toggling bBufferedRendering
textureCache_ - > NotifyFramebuffer ( vfb - > fb_address , vfb , NOTIFY_FB_DESTROYED ) ;
2015-11-14 13:24:51 +01:00
fbo_destroy ( vfb - > fbo_dx9 ) ;
vfb - > fbo_dx9 = nullptr ;
2014-09-09 22:56:54 -07:00
}
fbo_unbind ( ) ;
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
// Let's ignore rendering to targets that have not (yet) been displayed.
if ( vfb - > usageFlags & FB_USAGE_DISPLAYED_FRAMEBUFFER ) {
gstate_c . skipDrawReason & = ~ SKIPDRAW_NON_DISPLAYED_FB ;
} else {
gstate_c . skipDrawReason | = SKIPDRAW_NON_DISPLAYED_FB ;
2013-11-15 14:24:25 +01:00
}
2014-09-09 22:56:54 -07:00
}
textureCache_ - > NotifyFramebuffer ( vfb - > fb_address , vfb , NOTIFY_FB_UPDATED ) ;
2013-08-17 11:23:51 +02:00
2014-09-09 22:56:54 -07:00
// Copy depth pixel value from the read framebuffer to the draw framebuffer
if ( prevVfb & & ! g_Config . bDisableSlowFramebufEffects ) {
2015-11-14 13:24:51 +01:00
if ( ! prevVfb - > fbo_dx9 | | ! vfb - > fbo_dx9 | | ! useBufferedRendering_ | | ! prevVfb - > depthUpdated | | isClearingDepth ) {
2015-08-05 01:03:49 +02:00
// If depth wasn't updated, then we're at least "two degrees" away from the data.
// This is an optimization: it probably doesn't need to be copied in this case.
} else {
// TODO: Needs work
BlitFramebufferDepth ( prevVfb , vfb ) ;
}
2014-09-09 22:56:54 -07:00
}
if ( vfb - > drawnFormat ! = vfb - > format ) {
// TODO: Might ultimately combine this with the resize step in DoSetRenderFrameBuffer().
2015-02-26 08:41:10 -08:00
ReformatFramebufferFrom ( vfb , vfb - > drawnFormat ) ;
2014-09-09 22:56:54 -07:00
}
// ugly...
if ( gstate_c . curRTWidth ! = vfb - > width | | gstate_c . curRTHeight ! = vfb - > height ) {
shaderManager_ - > DirtyUniform ( DIRTY_PROJTHROUGHMATRIX ) ;
}
2014-09-13 22:01:32 -07:00
if ( gstate_c . curRTRenderWidth ! = vfb - > renderWidth | | gstate_c . curRTRenderHeight ! = vfb - > renderHeight ) {
shaderManager_ - > DirtyUniform ( DIRTY_PROJMATRIX ) ;
shaderManager_ - > DirtyUniform ( DIRTY_PROJTHROUGHMATRIX ) ;
}
2014-09-09 22:56:54 -07:00
}
void FramebufferManagerDX9 : : NotifyRenderFramebufferUpdated ( VirtualFramebuffer * vfb , bool vfbFormatChanged ) {
if ( vfbFormatChanged ) {
textureCache_ - > NotifyFramebuffer ( vfb - > fb_address , vfb , NOTIFY_FB_UPDATED ) ;
if ( vfb - > drawnFormat ! = vfb - > format ) {
2015-02-26 08:41:10 -08:00
ReformatFramebufferFrom ( vfb , vfb - > drawnFormat ) ;
2013-11-15 14:24:25 +01:00
}
}
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
// ugly...
if ( gstate_c . curRTWidth ! = vfb - > width | | gstate_c . curRTHeight ! = vfb - > height ) {
shaderManager_ - > DirtyUniform ( DIRTY_PROJTHROUGHMATRIX ) ;
}
2014-09-13 22:01:32 -07:00
if ( gstate_c . curRTRenderWidth ! = vfb - > renderWidth | | gstate_c . curRTRenderHeight ! = vfb - > renderHeight ) {
shaderManager_ - > DirtyUniform ( DIRTY_PROJMATRIX ) ;
shaderManager_ - > DirtyUniform ( DIRTY_PROJTHROUGHMATRIX ) ;
}
2013-08-17 11:23:51 +02:00
}
2015-02-26 08:41:10 -08:00
void FramebufferManagerDX9 : : ReformatFramebufferFrom ( VirtualFramebuffer * vfb , GEBufferFormat old ) {
2015-11-14 13:24:51 +01:00
if ( ! useBufferedRendering_ | | ! vfb - > fbo_dx9 ) {
2015-02-26 08:41:10 -08:00
return ;
}
2015-11-14 13:24:51 +01:00
fbo_bind_as_render_target ( vfb - > fbo_dx9 ) ;
2015-02-26 08:41:10 -08:00
// 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 ) {
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 ) ;
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 ) ;
pD3Ddevice - > SetVertexDeclaration ( pFramebufferVertexDecl ) ;
pD3Ddevice - > SetPixelShader ( pFramebufferPixelShader ) ;
pD3Ddevice - > SetVertexShader ( pFramebufferVertexShader ) ;
shaderManager_ - > DirtyLastShader ( ) ;
pD3Ddevice - > SetTexture ( 0 , nullptr ) ;
2015-11-12 14:47:43 +01:00
DXSetViewport ( 0 , 0 , vfb - > renderWidth , vfb - > renderHeight ) ;
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.
HRESULT hr = pD3Ddevice - > DrawPrimitiveUP ( D3DPT_TRIANGLEFAN , 2 , coord , 5 * sizeof ( float ) ) ;
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
}
RebindFramebuffer ( ) ;
}
2014-09-14 11:54:55 -07:00
void FramebufferManagerDX9 : : BlitFramebufferDepth ( VirtualFramebuffer * src , VirtualFramebuffer * dst ) {
if ( src - > z_address = = dst - > z_address & &
src - > z_stride ! = 0 & & dst - > z_stride ! = 0 & &
src - > renderWidth = = dst - > renderWidth & &
src - > renderHeight = = dst - > renderHeight ) {
2015-07-26 22:54:18 +02:00
// Doesn't work. Use a shader maybe?
/*fbo_unbind();
LPDIRECT3DTEXTURE9 srcTex = fbo_get_depth_texture ( src - > fbo ) ;
LPDIRECT3DTEXTURE9 dstTex = fbo_get_depth_texture ( dst - > fbo ) ;
if ( srcTex & & dstTex ) {
D3DSURFACE_DESC srcDesc ;
srcTex - > GetLevelDesc ( 0 , & srcDesc ) ;
D3DSURFACE_DESC dstDesc ;
dstTex - > GetLevelDesc ( 0 , & dstDesc ) ;
D3DLOCKED_RECT srcLock ;
D3DLOCKED_RECT dstLock ;
HRESULT srcLockRes = srcTex - > LockRect ( 0 , & srcLock , nullptr , D3DLOCK_READONLY ) ;
HRESULT dstLockRes = dstTex - > LockRect ( 0 , & dstLock , nullptr , 0 ) ;
if ( SUCCEEDED ( srcLockRes ) & & SUCCEEDED ( dstLockRes ) ) {
int pitch = std : : min ( srcLock . Pitch , dstLock . Pitch ) ;
u32 h = std : : min ( srcDesc . Height , dstDesc . Height ) ;
const u8 * srcp = ( const u8 * ) srcLock . pBits ;
u8 * dstp = ( u8 * ) dstLock . pBits ;
for ( u32 y = 0 ; y < h ; + + y ) {
memcpy ( dstp , srcp , pitch ) ;
dstp + = dstLock . Pitch ;
srcp + = srcLock . Pitch ;
2014-09-14 11:54:55 -07:00
}
}
2015-07-26 22:54:18 +02:00
if ( SUCCEEDED ( srcLockRes ) ) {
srcTex - > UnlockRect ( 0 ) ;
}
if ( SUCCEEDED ( dstLockRes ) ) {
dstTex - > UnlockRect ( 0 ) ;
}
2014-09-14 11:54:55 -07:00
}
2015-07-26 22:54:18 +02:00
RebindFramebuffer ( ) ; */
2014-09-14 11:54:55 -07:00
}
}
2015-11-14 13:24:51 +01:00
FBO_DX9 * FramebufferManagerDX9 : : GetTempFBO ( u16 w , u16 h , FBOColorDepth depth ) {
2015-01-19 08:41:53 -08:00
u64 key = ( ( u64 ) depth < < 32 ) | ( ( u32 ) w < < 16 ) | h ;
2014-09-13 22:39:54 -07:00
auto it = tempFBOs_ . find ( key ) ;
if ( it ! = tempFBOs_ . end ( ) ) {
it - > second . last_frame_used = gpuStats . numFlips ;
return it - > second . fbo ;
}
textureCache_ - > ForgetLastTexture ( ) ;
2015-11-14 13:24:51 +01:00
FBO_DX9 * fbo = fbo_create ( w , h , 1 , false , depth ) ;
2014-09-13 22:39:54 -07:00
if ( ! fbo )
return fbo ;
fbo_bind_as_render_target ( fbo ) ;
2015-11-29 10:51:38 -08:00
dxstate . viewport . force ( 0 , 0 , w , h ) ;
2015-11-03 22:37:19 -08:00
ClearBuffer ( true ) ;
2015-11-29 10:51:38 -08:00
dxstate . viewport . restore ( ) ;
2014-09-13 22:39:54 -07:00
const TempFBO info = { fbo , gpuStats . numFlips } ;
tempFBOs_ [ key ] = info ;
return fbo ;
}
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
u64 key = ( ( u64 ) desc . Format < < 32 ) | ( desc . Width < < 16 ) | desc . Height ;
auto it = offscreenSurfaces_ . find ( key ) ;
if ( it ! = offscreenSurfaces_ . end ( ) ) {
it - > second . last_frame_used = gpuStats . numFlips ;
return it - > second . surface ;
}
textureCache_ - > ForgetLastTexture ( ) ;
LPDIRECT3DSURFACE9 offscreen = nullptr ;
2015-06-21 19:57:58 -07:00
hr = pD3Ddevice - > CreateOffscreenPlainSurface ( desc . Width , desc . Height , desc . Format , D3DPOOL_SYSTEMMEM , & offscreen , NULL ) ;
2014-09-13 22:28:39 -07:00
if ( FAILED ( hr ) | | ! offscreen ) {
ERROR_LOG_REPORT ( G3D , " Unable to create offscreen surface %dx%d @%d " , desc . Width , desc . Height , desc . Format ) ;
return nullptr ;
}
const OffscreenSurface info = { offscreen , gpuStats . numFlips } ;
offscreenSurfaces_ [ key ] = info ;
return offscreen ;
}
2015-09-13 11:14:51 -07:00
void FramebufferManagerDX9 : : BindFramebufferColor ( int stage , VirtualFramebuffer * framebuffer , int flags ) {
2014-09-17 23:26:20 +02:00
if ( framebuffer = = NULL ) {
framebuffer = currentRenderVfb_ ;
}
if ( ! framebuffer - > fbo | | ! useBufferedRendering_ ) {
2014-09-21 12:11:17 -07:00
pD3Ddevice - > 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 ;
}
if ( ! skipCopy & & currentRenderVfb_ & & framebuffer - > fb_address = = gstate . getFrameBufRawAddress ( ) ) {
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
2015-11-14 13:24:51 +01:00
FBO_DX9 * renderCopy = GetTempFBO ( framebuffer - > renderWidth , framebuffer - > renderHeight , ( FBOColorDepth ) framebuffer - > colorDepth ) ;
2014-09-17 23:26:20 +02:00
if ( renderCopy ) {
VirtualFramebuffer copyInfo = * framebuffer ;
2015-11-14 13:24:51 +01:00
copyInfo . fbo_dx9 = renderCopy ;
2015-09-13 11:14:51 -07:00
int x = 0 ;
int y = 0 ;
int w = framebuffer - > drawnWidth ;
int h = framebuffer - > drawnHeight ;
// If max is not > min, we probably could not detect it. Skip.
// See the vertex decoder, where this is updated.
2015-11-09 23:28:15 -08:00
if ( ( flags & BINDFBCOLOR_MAY_COPY_WITH_UV ) = = BINDFBCOLOR_MAY_COPY_WITH_UV & & gstate_c . vertBounds . maxU > gstate_c . vertBounds . minU ) {
2015-09-13 14:52:10 -07:00
x = gstate_c . vertBounds . minU ;
y = gstate_c . vertBounds . minV ;
w = gstate_c . vertBounds . maxU - x ;
h = gstate_c . vertBounds . maxV - y ;
2015-09-12 19:43:02 -07:00
// If we bound a framebuffer, apply the byte offset as pixels to the copy too.
if ( flags & BINDFBCOLOR_APPLY_TEX_OFFSET ) {
x + = gstate_c . curTextureXOffset ;
y + = gstate_c . curTextureYOffset ;
}
2015-09-13 11:14:51 -07:00
}
2015-11-01 13:32:03 +01:00
BlitFramebuffer ( & copyInfo , x , y , framebuffer , x , y , w , h , 0 ) ;
2014-09-17 23:26:20 +02:00
RebindFramebuffer ( ) ;
2014-09-21 12:11:17 -07:00
pD3Ddevice - > SetTexture ( stage , fbo_get_color_texture ( renderCopy ) ) ;
2014-09-17 23:26:20 +02:00
} else {
2015-11-14 13:24:51 +01:00
pD3Ddevice - > SetTexture ( stage , fbo_get_color_texture ( framebuffer - > fbo_dx9 ) ) ;
2014-09-17 23:26:20 +02:00
}
} else {
2015-11-14 13:24:51 +01:00
pD3Ddevice - > SetTexture ( stage , fbo_get_color_texture ( framebuffer - > fbo_dx9 ) ) ;
2014-09-17 23:26:20 +02:00
}
}
2013-11-15 14:24:25 +01:00
void FramebufferManagerDX9 : : CopyDisplayToOutput ( ) {
fbo_unbind ( ) ;
2015-12-30 17:44:32 -08:00
currentRenderVfb_ = 0 ;
if ( displayFramebufPtr_ = = 0 ) {
DEBUG_LOG ( SCEGE , " Display disabled, displaying only black " ) ;
// No framebuffer to display! Clear to black.
ClearBuffer ( ) ;
return ;
}
2015-11-12 14:47:43 +01:00
if ( useBufferedRendering_ ) {
2015-11-18 12:25:54 +01:00
// In buffered, we no longer clear the backbuffer before we start rendering.
ClearBuffer ( ) ;
2015-11-12 14:47:43 +01:00
DXSetViewport ( 0 , 0 , PSP_CoreParameter ( ) . pixelWidth , PSP_CoreParameter ( ) . pixelHeight ) ;
}
2013-08-25 13:56:29 +02:00
2014-09-13 12:07:30 -07:00
u32 offsetX = 0 ;
u32 offsetY = 0 ;
2014-09-09 08:12:42 -07:00
VirtualFramebuffer * vfb = GetVFBAt ( displayFramebufPtr_ ) ;
2014-09-13 12:07:30 -07:00
if ( ! vfb ) {
// Let's search for a framebuf within this range.
const u32 addr = ( displayFramebufPtr_ & 0x03FFFFFF ) | 0x04000000 ;
for ( size_t i = 0 ; i < vfbs_ . size ( ) ; + + i ) {
VirtualFramebuffer * v = vfbs_ [ i ] ;
const u32 v_addr = ( v - > fb_address & 0x03FFFFFF ) | 0x04000000 ;
const u32 v_size = FramebufferByteSize ( v ) ;
if ( addr > = v_addr & & addr < v_addr + v_size ) {
const u32 dstBpp = v - > format = = GE_FORMAT_8888 ? 4 : 2 ;
const u32 v_offsetX = ( ( addr - v_addr ) / dstBpp ) % v - > fb_stride ;
const u32 v_offsetY = ( ( addr - v_addr ) / dstBpp ) / v - > fb_stride ;
// We have enough space there for the display, right?
if ( v_offsetX + 480 > ( u32 ) v - > fb_stride | | v - > bufferHeight < v_offsetY + 272 ) {
continue ;
}
// Check for the closest one.
if ( offsetY = = 0 | | offsetY > v_offsetY ) {
offsetX = v_offsetX ;
offsetY = v_offsetY ;
vfb = v ;
}
}
}
if ( vfb ) {
// Okay, we found one above.
INFO_LOG_REPORT_ONCE ( displayoffset , HLE , " Rendering from framebuf with offset %08x -> %08x+%dx%d " , addr , vfb - > fb_address , offsetX , offsetY ) ;
}
}
if ( vfb & & vfb - > format ! = displayFormat_ ) {
if ( vfb - > last_frame_render + FBO_OLD_AGE < gpuStats . numFlips ) {
// The game probably switched formats on us.
vfb - > format = displayFormat_ ;
} else {
vfb = 0 ;
}
}
2013-11-15 14:24:25 +01:00
if ( ! vfb ) {
if ( Memory : : IsValidAddress ( displayFramebufPtr_ ) ) {
// The game is displaying something directly from RAM. In GTA, it's decoded video.
// First check that it's not a known RAM copy of a VRAM framebuffer though, as in MotoGP
2014-09-13 15:40:55 -07:00
for ( auto iter = knownFramebufferRAMCopies_ . begin ( ) ; iter ! = knownFramebufferRAMCopies_ . end ( ) ; + + iter ) {
2013-11-15 14:24:25 +01:00
if ( iter - > second = = displayFramebufPtr_ ) {
vfb = GetVFBAt ( iter - > first ) ;
}
}
if ( ! vfb ) {
// Just a pointer to plain memory to draw. Draw it.
2015-11-01 15:34:53 +01:00
DrawFramebufferToOutput ( Memory : : GetPointer ( displayFramebufPtr_ ) , displayFormat_ , displayStride_ , true ) ;
2013-11-15 14:24:25 +01:00
return ;
}
} else {
DEBUG_LOG ( SCEGE , " Found no FBO to display! displayFBPtr = %08x " , displayFramebufPtr_ ) ;
2015-11-18 12:25:54 +01:00
// No framebuffer to display! Clear to black. If buffered, we already did that.
if ( ! useBufferedRendering_ )
ClearBuffer ( ) ;
2013-11-15 14:24:25 +01:00
return ;
}
2013-08-24 19:07:15 +02:00
}
2013-11-15 14:24:25 +01:00
vfb - > usageFlags | = FB_USAGE_DISPLAYED_FRAMEBUFFER ;
2015-03-14 14:58:32 -07:00
vfb - > last_frame_displayed = gpuStats . numFlips ;
2013-11-15 14:24:25 +01:00
vfb - > dirtyAfterDisplay = false ;
vfb - > reallyDirtyAfterDisplay = false ;
if ( prevDisplayFramebuf_ ! = displayFramebuf_ ) {
prevPrevDisplayFramebuf_ = prevDisplayFramebuf_ ;
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
if ( displayFramebuf_ ! = vfb ) {
prevDisplayFramebuf_ = displayFramebuf_ ;
}
displayFramebuf_ = vfb ;
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
if ( vfb - > fbo ) {
DEBUG_LOG ( SCEGE , " Displaying FBO %08x " , vfb - > fb_address ) ;
DisableState ( ) ;
2015-11-14 13:24:51 +01:00
LPDIRECT3DTEXTURE9 colorTexture = fbo_get_color_texture ( vfb - > fbo_dx9 ) ;
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
// Output coordinates
float x , y , w , h ;
2015-05-12 22:44:02 +02:00
int uvRotation = ( g_Config . iRenderingMode ! = FB_NON_BUFFERED_MODE ) ? g_Config . iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL ;
2015-11-03 00:24:19 +01:00
CenterDisplayOutputRect ( & x , & y , & w , & h , 480.0f , 272.0f , ( float ) PSP_CoreParameter ( ) . pixelWidth , ( float ) PSP_CoreParameter ( ) . pixelHeight , uvRotation ) ;
2013-08-19 20:36:43 +02:00
2014-09-13 12:07:30 -07:00
const float u0 = offsetX / ( float ) vfb - > bufferWidth ;
const float v0 = offsetY / ( float ) vfb - > bufferHeight ;
const float u1 = ( 480.0f + offsetX ) / ( float ) vfb - > bufferWidth ;
const float v1 = ( 272.0f + offsetY ) / ( float ) vfb - > bufferHeight ;
2013-11-15 14:24:25 +01:00
if ( 1 ) {
2014-09-14 00:20:59 -07:00
const u32 rw = PSP_CoreParameter ( ) . pixelWidth ;
const u32 rh = PSP_CoreParameter ( ) . pixelHeight ;
const RECT srcRect = { ( LONG ) ( u0 * vfb - > renderWidth ) , ( LONG ) ( v0 * vfb - > renderHeight ) , ( LONG ) ( u1 * vfb - > renderWidth ) , ( LONG ) ( v1 * vfb - > renderHeight ) } ;
2015-11-29 10:52:49 -08:00
const RECT dstRect = { ( LONG ) ( x * rw / w ) , ( LONG ) ( y * rh / h ) , ( LONG ) ( ( x + w ) * rw / w ) , ( LONG ) ( ( y + h ) * rh / h ) } ;
2015-11-14 13:24:51 +01:00
HRESULT hr = fbo_blit_color ( vfb - > fbo_dx9 , & srcRect , nullptr , & dstRect , g_Config . iBufFilter = = SCALE_LINEAR ? D3DTEXF_LINEAR : D3DTEXF_POINT ) ;
2015-01-06 13:00:03 +01:00
if ( FAILED ( hr ) ) {
ERROR_LOG_REPORT_ONCE ( blit_fail , G3D , " fbo_blit_color failed on display: %08x " , hr ) ;
2015-11-12 14:47:43 +01:00
DXSetViewport ( 0 , 0 , PSP_CoreParameter ( ) . pixelWidth , PSP_CoreParameter ( ) . pixelHeight ) ;
2014-09-13 20:31:01 -07:00
// These are in the output display coordinates
if ( g_Config . iBufFilter = = SCALE_LINEAR ) {
dxstate . texMagFilter . set ( D3DTEXF_LINEAR ) ;
dxstate . texMinFilter . set ( D3DTEXF_LINEAR ) ;
} else {
dxstate . texMagFilter . set ( D3DTEXF_POINT ) ;
dxstate . texMinFilter . set ( D3DTEXF_POINT ) ;
}
dxstate . texMipFilter . set ( D3DTEXF_NONE ) ;
dxstate . texMipLodBias . set ( 0 ) ;
2015-11-01 13:32:03 +01:00
DrawActiveTexture ( colorTexture , x , y , w , h , ( float ) PSP_CoreParameter ( ) . pixelWidth , ( float ) PSP_CoreParameter ( ) . pixelHeight , u0 , v0 , u1 , v1 , uvRotation ) ;
2015-01-06 13:00:03 +01:00
}
2013-11-15 14:24:25 +01:00
}
/*
else if ( usePostShader_ & & extraFBOs_ . size ( ) = = 1 & & ! postShaderAtOutputResolution_ ) {
// An additional pass, post-processing shader to the extra FBO.
fbo_bind_as_render_target ( extraFBOs_ [ 0 ] ) ;
int fbo_w , fbo_h ;
fbo_get_dimensions ( extraFBOs_ [ 0 ] , & fbo_w , & fbo_h ) ;
2015-11-12 14:47:43 +01:00
DXSetViewport ( 0 , 0 , fbo_w , fbo_h ) ;
2013-11-15 14:24:25 +01:00
DrawActiveTexture ( colorTexture , 0 , 0 , fbo_w , fbo_h , fbo_w , fbo_h , true , 1.0f , 1.0f , postShaderProgram_ ) ;
2013-08-20 18:46:57 +02:00
2013-11-15 14:24:25 +01:00
fbo_unbind ( ) ;
2013-08-19 20:36:43 +02:00
2013-11-15 14:24:25 +01:00
// Use the extra FBO, with applied post-processing shader, as a texture.
// fbo_bind_color_as_texture(extraFBOs_[0], 0);
if ( extraFBOs_ . size ( ) = = 0 ) {
ERROR_LOG ( G3D , " WTF? " ) ;
return ;
}
colorTexture = fbo_get_color_texture ( extraFBOs_ [ 0 ] ) ;
2015-11-12 14:47:43 +01:00
DXSetViewport ( 0 , 0 , PSP_CoreParameter ( ) . pixelWidth , PSP_CoreParameter ( ) . pixelHeight ) ;
2013-11-15 14:24:25 +01:00
// These are in the output display coordinates
DrawActiveTexture ( colorTexture , x , y , w , h , ( float ) PSP_CoreParameter ( ) . pixelWidth , ( float ) PSP_CoreParameter ( ) . pixelHeight , true , 480.0f / ( float ) vfb - > width , 272.0f / ( float ) vfb - > height ) ;
} else {
// Use post-shader, but run shader at output resolution.
2015-11-12 14:47:43 +01:00
DXSetViewport ( 0 , 0 , PSP_CoreParameter ( ) . pixelWidth , PSP_CoreParameter ( ) . pixelHeight ) ;
2013-11-15 14:24:25 +01:00
// These are in the output display coordinates
DrawActiveTexture ( colorTexture , x , y , w , h , ( float ) PSP_CoreParameter ( ) . pixelWidth , ( float ) PSP_CoreParameter ( ) . pixelHeight , true , 480.0f / ( float ) vfb - > width , 272.0f / ( float ) vfb - > height , postShaderProgram_ ) ;
}
*/
pD3Ddevice - > SetTexture ( 0 , NULL ) ;
}
2015-11-12 14:47:43 +01:00
dxstate . viewport . restore ( ) ;
2013-08-17 11:23:51 +02:00
}
2014-09-13 15:09:30 -07:00
void FramebufferManagerDX9 : : ReadFramebufferToMemory ( VirtualFramebuffer * vfb , bool sync , int x , int y , int w , int h ) {
2013-11-15 14:24:25 +01:00
#if 0
if ( sync ) {
PackFramebufferAsync_ ( NULL ) ; // flush async just in case when we go for synchronous update
}
# endif
2013-08-19 20:36:43 +02:00
2014-09-13 15:09:30 -07:00
if ( vfb ) {
2015-11-01 13:32:03 +01:00
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
2013-11-15 14:24:25 +01:00
// For now we'll keep these on the same struct as the ones that can get displayed
// (and blatantly copy work already done above while at it).
2014-09-09 08:12:42 -07:00
VirtualFramebuffer * nvfb = 0 ;
2013-11-15 14:24:25 +01:00
// We maintain a separate vector of framebuffer objects for blitting.
for ( size_t i = 0 ; i < bvfbs_ . size ( ) ; + + i ) {
2014-09-09 08:12:42 -07:00
VirtualFramebuffer * v = bvfbs_ [ i ] ;
2014-12-18 23:03:19 -08:00
if ( v - > fb_address = = vfb - > fb_address & & v - > format = = vfb - > format ) {
2013-11-15 14:24:25 +01:00
if ( v - > bufferWidth = = vfb - > bufferWidth & & v - > bufferHeight = = vfb - > bufferHeight ) {
nvfb = v ;
v - > fb_stride = vfb - > fb_stride ;
v - > width = vfb - > width ;
v - > height = vfb - > height ;
break ;
}
2013-08-17 11:23:51 +02:00
}
}
2013-11-15 14:24:25 +01:00
// Create a new fbo if none was found for the size
if ( ! nvfb ) {
2014-09-09 08:12:42 -07:00
nvfb = new VirtualFramebuffer ( ) ;
2015-11-14 13:24:51 +01:00
nvfb - > fbo_dx9 = nullptr ;
2013-11-15 14:24:25 +01:00
nvfb - > fb_address = vfb - > fb_address ;
nvfb - > fb_stride = vfb - > fb_stride ;
nvfb - > z_address = vfb - > z_address ;
nvfb - > z_stride = vfb - > z_stride ;
nvfb - > width = vfb - > width ;
nvfb - > height = vfb - > height ;
2014-12-18 23:03:19 -08:00
nvfb - > renderWidth = vfb - > bufferWidth ;
nvfb - > renderHeight = vfb - > bufferHeight ;
2013-11-15 14:24:25 +01:00
nvfb - > bufferWidth = vfb - > bufferWidth ;
nvfb - > bufferHeight = vfb - > bufferHeight ;
nvfb - > format = vfb - > format ;
2014-09-13 15:09:30 -07:00
nvfb - > drawnWidth = vfb - > drawnWidth ;
nvfb - > drawnHeight = vfb - > drawnHeight ;
nvfb - > drawnFormat = vfb - > format ;
2013-11-15 14:24:25 +01:00
nvfb - > usageFlags = FB_USAGE_RENDERTARGET ;
nvfb - > dirtyAfterDisplay = true ;
2014-09-13 18:25:45 -07:00
nvfb - > colorDepth = FBO_8888 ;
2013-08-17 11:23:51 +02:00
2014-09-13 15:09:30 -07:00
textureCache_ - > ForgetLastTexture ( ) ;
2015-11-14 13:24:51 +01:00
nvfb - > fbo_dx9 = fbo_create ( nvfb - > width , nvfb - > height , 1 , true , ( FBOColorDepth ) nvfb - > colorDepth ) ;
if ( ! ( nvfb - > fbo_dx9 ) ) {
2013-11-15 14:24:25 +01:00
ERROR_LOG ( SCEGE , " Error creating FBO! %i x %i " , nvfb - > renderWidth , nvfb - > renderHeight ) ;
2015-01-18 13:18:17 -08:00
delete nvfb ;
2013-11-15 14:24:25 +01:00
return ;
}
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
nvfb - > last_frame_render = gpuStats . numFlips ;
bvfbs_ . push_back ( nvfb ) ;
2015-11-14 13:24:51 +01:00
fbo_bind_as_render_target ( nvfb - > fbo_dx9 ) ;
2013-11-15 14:24:25 +01:00
ClearBuffer ( ) ;
} else {
nvfb - > usageFlags | = FB_USAGE_RENDERTARGET ;
gstate_c . textureChanged = true ;
nvfb - > last_frame_render = gpuStats . numFlips ;
nvfb - > dirtyAfterDisplay = true ;
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
#if 0
if ( nvfb - > fbo ) {
fbo_bind_as_render_target ( nvfb - > fbo ) ;
}
2013-08-19 20:36:43 +02:00
2013-11-15 14:24:25 +01:00
// Some tiled mobile GPUs benefit IMMENSELY from clearing an FBO before rendering
// to it. This broke stuff before, so now it only clears on the first use of an
// FBO in a frame. This means that some games won't be able to avoid the on-some-GPUs
// performance-crushing framebuffer reloads from RAM, but we'll have to live with that.
if ( nvfb - > last_frame_render ! = gpuStats . numFlips ) {
ClearBuffer ( ) ;
}
2013-08-17 11:23:51 +02:00
# endif
2013-11-15 14:24:25 +01:00
}
2013-08-17 11:23:51 +02:00
2014-09-13 15:09:30 -07:00
if ( gameUsesSequentialCopies_ ) {
// Ignore the x/y/etc., read the entire thing.
x = 0 ;
y = 0 ;
w = vfb - > width ;
h = vfb - > height ;
}
if ( x = = 0 & & y = = 0 & & w = = vfb - > width & & h = = vfb - > height ) {
vfb - > memoryUpdated = true ;
} else {
const static int FREQUENT_SEQUENTIAL_COPIES = 3 ;
static int frameLastCopy = 0 ;
static u32 bufferLastCopy = 0 ;
static int copiesThisFrame = 0 ;
if ( frameLastCopy ! = gpuStats . numFlips | | bufferLastCopy ! = vfb - > fb_address ) {
frameLastCopy = gpuStats . numFlips ;
bufferLastCopy = vfb - > fb_address ;
copiesThisFrame = 0 ;
}
if ( + + copiesThisFrame > FREQUENT_SEQUENTIAL_COPIES ) {
gameUsesSequentialCopies_ = true ;
}
}
2015-11-01 13:32:03 +01:00
BlitFramebuffer ( nvfb , x , y , vfb , x , y , w , h , 0 ) ;
2013-08-17 11:23:51 +02:00
2014-09-13 16:37:59 -07:00
PackFramebufferDirectx9_ ( nvfb , x , y , w , h ) ;
2014-09-13 14:26:39 -07:00
RebindFramebuffer ( ) ;
2013-11-15 14:24:25 +01:00
}
2013-08-17 11:23:51 +02:00
}
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_ ) {
// This can happen if they recently switched from non-buffered.
2013-11-15 14:24:25 +01:00
fbo_unbind ( ) ;
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-14 13:24:51 +01:00
LPDIRECT3DSURFACE9 srcSurf = fbo_get_color_for_read ( src - > fbo_dx9 ) ;
LPDIRECT3DSURFACE9 dstSurf = fbo_get_color_for_write ( dst - > fbo_dx9 ) ;
2015-11-01 13:32:03 +01:00
RECT srcRect = { srcX1 , srcY1 , srcX2 , srcY2 } ;
RECT dstRect = { dstX1 , dstY1 , dstX2 , dstY2 } ;
D3DSURFACE_DESC desc ;
srcSurf - > GetDesc ( & desc ) ;
srcRect . right = std : : min ( srcRect . right , ( LONG ) desc . Width ) ;
srcRect . bottom = std : : min ( srcRect . bottom , ( LONG ) desc . Height ) ;
dstSurf - > GetDesc ( & desc ) ;
dstRect . right = std : : min ( dstRect . right , ( LONG ) desc . Width ) ;
dstRect . bottom = std : : min ( dstRect . bottom , ( LONG ) desc . Height ) ;
// Direct3D 9 doesn't support rect -> self.
2015-11-14 13:24:51 +01:00
FBO_DX9 * srcFBO = src - > fbo_dx9 ;
2015-11-01 13:32:03 +01:00
if ( src = = dst ) {
2015-11-14 13:24:51 +01:00
FBO_DX9 * tempFBO = GetTempFBO ( src - > renderWidth , src - > renderHeight , ( FBOColorDepth ) src - > colorDepth ) ;
HRESULT hr = fbo_blit_color ( src - > fbo_dx9 , & srcRect , tempFBO , & srcRect , D3DTEXF_POINT ) ;
2015-11-01 13:32:03 +01:00
if ( SUCCEEDED ( hr ) ) {
srcFBO = tempFBO ;
2014-09-13 22:39:54 -07:00
}
2015-11-01 13:32:03 +01:00
}
2014-09-13 22:39:54 -07:00
2015-11-14 13:24:51 +01:00
HRESULT hr = fbo_blit_color ( srcFBO , & srcRect , dst - > fbo_dx9 , & dstRect , D3DTEXF_POINT ) ;
2015-11-01 13:32:03 +01:00
if ( FAILED ( hr ) ) {
ERROR_LOG_REPORT ( G3D , " fbo_blit_color failed in blit: %08x (%08x -> %08x) " , hr , 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
2013-11-15 14:24:25 +01:00
// TODO: SSE/NEON
// Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :)
2014-09-13 16:37:59 -07:00
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 ) {
2013-11-15 14:24:25 +01:00
return ;
2014-09-13 16:37:59 -07:00
} else {
for ( u32 y = 0 ; y < height ; + + y ) {
ConvertBGRA8888ToRGBA8888 ( dst32 , src32 , width ) ;
src32 + = srcStride ;
dst32 + = dstStride ;
}
2013-08-20 18:46:57 +02:00
}
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
}
}
2014-09-13 16:37:59 -07:00
void FramebufferManagerDX9 : : PackFramebufferDirectx9_ ( VirtualFramebuffer * vfb , int x , int y , int w , int h ) {
if ( ! vfb - > fbo ) {
ERROR_LOG_REPORT_ONCE ( vfbfbozero , SCEGE , " PackFramebufferDirectx9_: vfb->fbo == 0 " ) ;
2013-11-15 15:15:12 +01:00
fbo_unbind ( ) ;
return ;
}
2014-09-13 16:37:59 -07:00
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.
DEBUG_LOG ( HLE , " Reading framebuffer to mem, fb_address = %08x " , fb_address ) ;
2015-11-14 13:24:51 +01:00
LPDIRECT3DSURFACE9 renderTarget = fbo_get_color_for_read ( vfb - > fbo_dx9 ) ;
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 ) {
HRESULT hr = pD3Ddevice - > 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.
2014-09-13 17:14:29 -07:00
ConvertFromRGBA8888 ( 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
2013-11-15 14:24:25 +01:00
void FramebufferManagerDX9 : : EndFrame ( ) {
if ( resized_ ) {
DestroyAllFBOs ( ) ;
2015-09-23 12:25:38 +02:00
// Actually, auto mode should be more granular...
// Round up to a zoom factor for the render size.
int zoom = g_Config . iInternalResolution ;
if ( zoom = = 0 ) { // auto mode
// Use the longest dimension
2015-09-25 19:08:48 +02:00
if ( ! g_Config . IsPortrait ( ) ) {
zoom = ( PSP_CoreParameter ( ) . pixelWidth + 479 ) / 480 ;
2015-09-23 12:25:38 +02:00
} else {
2015-09-25 19:08:48 +02:00
zoom = ( PSP_CoreParameter ( ) . pixelHeight + 479 ) / 480 ;
2015-09-23 12:25:38 +02:00
}
}
if ( zoom < = 1 )
zoom = 1 ;
if ( g_Config . IsPortrait ( ) ) {
PSP_CoreParameter ( ) . renderWidth = 272 * zoom ;
PSP_CoreParameter ( ) . renderHeight = 480 * zoom ;
} else {
PSP_CoreParameter ( ) . renderWidth = 480 * zoom ;
PSP_CoreParameter ( ) . renderHeight = 272 * zoom ;
}
2015-09-27 19:59:47 +02:00
UpdateSize ( ) ;
2015-11-27 00:16:03 +01:00
// Seems related - if you're ok with numbers all the time, show some more :)
if ( g_Config . iShowFPSCounter ! = 0 ) {
ShowScreenResolution ( ) ;
}
2013-11-15 14:24:25 +01:00
resized_ = false ;
}
2013-11-15 15:15:12 +01:00
#if 0
// We flush to memory last requested framebuffer, if any
PackFramebufferAsync_ ( NULL ) ;
# endif
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 : : DeviceLost ( ) {
DestroyAllFBOs ( ) ;
resized_ = false ;
}
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
std : : vector < FramebufferInfo > FramebufferManagerDX9 : : GetFramebufferList ( ) {
std : : vector < FramebufferInfo > list ;
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
for ( size_t i = 0 ; i < vfbs_ . size ( ) ; + + i ) {
2014-09-09 08:12:42 -07:00
VirtualFramebuffer * vfb = vfbs_ [ i ] ;
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
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 ) ;
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
return list ;
}
2013-08-17 11:23:51 +02:00
2013-11-15 14:24:25 +01:00
void FramebufferManagerDX9 : : DecimateFBOs ( ) {
2015-11-12 15:26:06 +01:00
if ( g_Config . iRenderingMode ! = FB_NON_BUFFERED_MODE ) {
fbo_unbind ( ) ;
}
2013-11-15 14:24:25 +01:00
currentRenderVfb_ = 0 ;
bool updateVram = ! ( g_Config . iRenderingMode = = FB_NON_BUFFERED_MODE | | g_Config . iRenderingMode = = FB_BUFFERED_MODE ) ;
for ( size_t i = 0 ; i < vfbs_ . size ( ) ; + + i ) {
2014-09-09 08:12:42 -07:00
VirtualFramebuffer * vfb = vfbs_ [ i ] ;
int age = frameLastFramebufUsed_ - std : : max ( vfb - > last_frame_render , vfb - > last_frame_used ) ;
2013-11-15 14:24:25 +01:00
2014-09-13 15:09:30 -07:00
if ( ShouldDownloadFramebuffer ( vfb ) & & age = = 0 & & ! vfb - > memoryUpdated ) {
ReadFramebufferToMemory ( vfb , false , 0 , 0 , vfb - > width , vfb - > height ) ;
}
2013-11-15 14:24:25 +01:00
2015-03-23 20:29:51 +08:00
// Let's also "decimate" the usageFlags.
UpdateFramebufUsage ( vfb ) ;
2015-03-14 14:58:32 -07:00
if ( vfb ! = displayFramebuf_ & & vfb ! = prevDisplayFramebuf_ & & vfb ! = prevPrevDisplayFramebuf_ ) {
if ( age > FBO_OLD_AGE ) {
INFO_LOG ( SCEGE , " Decimating FBO for %08x (%i x %i x %i), age %i " , vfb - > fb_address , vfb - > width , vfb - > height , vfb - > format , age ) ;
DestroyFramebuf ( vfb ) ;
vfbs_ . erase ( vfbs_ . begin ( ) + i - - ) ;
}
2013-11-15 14:24:25 +01:00
}
}
2014-09-13 22:39:54 -07:00
for ( auto it = tempFBOs_ . begin ( ) ; it ! = tempFBOs_ . end ( ) ; ) {
int age = frameLastFramebufUsed_ - it - > second . last_frame_used ;
if ( age > FBO_OLD_AGE ) {
fbo_destroy ( it - > second . fbo ) ;
tempFBOs_ . erase ( it + + ) ;
} else {
+ + it ;
}
}
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 ( ) ;
offscreenSurfaces_ . erase ( it + + ) ;
} else {
+ + it ;
}
}
2013-11-15 14:24:25 +01:00
// Do the same for ReadFramebuffersToMemory's VFBs
for ( size_t i = 0 ; i < bvfbs_ . size ( ) ; + + i ) {
2014-09-09 08:12:42 -07:00
VirtualFramebuffer * vfb = bvfbs_ [ i ] ;
int age = frameLastFramebufUsed_ - vfb - > last_frame_render ;
2013-11-15 14:24:25 +01:00
if ( age > FBO_OLD_AGE ) {
INFO_LOG ( SCEGE , " Decimating FBO for %08x (%i x %i x %i), age %i " , vfb - > fb_address , vfb - > width , vfb - > height , vfb - > format , age ) ;
DestroyFramebuf ( vfb ) ;
bvfbs_ . erase ( bvfbs_ . begin ( ) + i - - ) ;
}
2013-08-17 11:23:51 +02:00
}
}
2013-11-15 14:24:25 +01:00
void FramebufferManagerDX9 : : DestroyAllFBOs ( ) {
2013-08-17 11:23:51 +02:00
fbo_unbind ( ) ;
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 ] ;
2013-11-15 14:24:25 +01:00
INFO_LOG ( SCEGE , " Destroying FBO for %08x : %i x %i x %i " , vfb - > fb_address , vfb - > width , vfb - > height , vfb - > format ) ;
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 ( ) ;
2014-09-13 22:39:54 -07:00
for ( auto it = tempFBOs_ . begin ( ) , end = tempFBOs_ . end ( ) ; it ! = end ; + + it ) {
fbo_destroy ( it - > second . fbo ) ;
}
tempFBOs_ . clear ( ) ;
2014-09-13 22:28:39 -07:00
for ( auto it = offscreenSurfaces_ . begin ( ) , end = offscreenSurfaces_ . end ( ) ; it ! = end ; + + it ) {
it - > second . surface - > Release ( ) ;
}
offscreenSurfaces_ . clear ( ) ;
DisableState ( ) ;
2013-11-15 14:24:25 +01:00
}
2014-09-13 14:23:18 -07:00
void FramebufferManagerDX9 : : FlushBeforeCopy ( ) {
// Flush anything not yet drawn before blitting, downloading, or uploading.
// This might be a stalled list, or unflushed before a block transfer, etc.
2015-08-05 02:43:40 +02:00
// 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.
2015-07-26 22:38:40 +02:00
SetRenderFrameBuffer ( gstate_c . framebufChanged , gstate_c . skipDrawReason ) ;
2014-09-13 14:23:18 -07:00
transformDraw_ - > Flush ( ) ;
}
2013-11-15 14:24:25 +01:00
void FramebufferManagerDX9 : : Resized ( ) {
resized_ = true ;
2013-08-17 11:23:51 +02:00
}
2013-11-15 14:24:25 +01:00
bool FramebufferManagerDX9 : : GetCurrentFramebuffer ( GPUDebugBuffer & buffer ) {
2014-08-24 21:23:23 -07:00
u32 fb_address = gstate . getFrameBufRawAddress ( ) ;
int fb_stride = gstate . FrameBufStride ( ) ;
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?
buffer = GPUDebugBuffer ( Memory : : GetPointer ( fb_address | 0x04000000 ) , fb_stride , 512 , gstate . FrameBufFormat ( ) ) ;
return true ;
}
2015-11-14 13:24:51 +01:00
LPDIRECT3DSURFACE9 renderTarget = vfb - > fbo ? fbo_get_color_for_read ( vfb - > fbo_dx9 ) : nullptr ;
2014-12-20 08:31:56 -08:00
bool success = false ;
if ( renderTarget ) {
2015-06-21 12:50:02 -07:00
LPDIRECT3DSURFACE9 offscreen = GetOffscreenSurface ( renderTarget , vfb ) ;
2014-12-20 08:31:56 -08:00
if ( offscreen ) {
success = GetRenderTargetFramebuffer ( renderTarget , offscreen , vfb - > renderWidth , vfb - > renderHeight , buffer ) ;
}
}
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
2014-12-20 08:31:56 -08:00
bool FramebufferManagerDX9 : : GetDisplayFramebuffer ( GPUDebugBuffer & buffer ) {
fbo_unbind ( ) ;
LPDIRECT3DSURFACE9 renderTarget = nullptr ;
HRESULT hr = pD3Ddevice - > GetRenderTarget ( 0 , & renderTarget ) ;
bool success = false ;
if ( renderTarget & & SUCCEEDED ( hr ) ) {
D3DSURFACE_DESC desc ;
renderTarget - > GetDesc ( & desc ) ;
LPDIRECT3DSURFACE9 offscreen = nullptr ;
HRESULT hr = pD3Ddevice - > CreateOffscreenPlainSurface ( desc . Width , desc . Height , desc . Format , D3DPOOL_SYSTEMMEM , & offscreen , NULL ) ;
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-08-24 21:23:23 -07:00
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 ;
2014-12-20 08:31:56 -08:00
HRESULT hr = pD3Ddevice - > 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
}
bool FramebufferManagerDX9 : : GetCurrentDepthbuffer ( GPUDebugBuffer & buffer ) {
2014-09-14 11:14:56 -07:00
u32 fb_address = gstate . getFrameBufRawAddress ( ) ;
int fb_stride = gstate . FrameBufStride ( ) ;
u32 z_address = gstate . getDepthBufRawAddress ( ) ;
int z_stride = gstate . DepthBufStride ( ) ;
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 ;
}
bool success = false ;
2015-11-14 13:24:51 +01:00
LPDIRECT3DTEXTURE9 tex = fbo_get_depth_texture ( vfb - > fbo_dx9 ) ;
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 ;
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
}
bool FramebufferManagerDX9 : : GetCurrentStencilbuffer ( GPUDebugBuffer & buffer ) {
2014-09-14 11:14:56 -07:00
u32 fb_address = gstate . getFrameBufRawAddress ( ) ;
int fb_stride = gstate . FrameBufStride ( ) ;
u32 z_address = gstate . getDepthBufRawAddress ( ) ;
int z_stride = gstate . DepthBufStride ( ) ;
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 ;
}
bool success = false ;
2015-11-14 13:24:51 +01:00
LPDIRECT3DTEXTURE9 tex = fbo_get_depth_texture ( vfb - > fbo_dx9 ) ;
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