2013-06-01 13:10:30 +00:00
# include <assert.h>
2015-01-28 13:58:55 +00:00
# include <math.h>
2013-04-05 06:13:26 +00:00
# include "OpenGL.h"
# include "FrameBuffer.h"
2013-06-01 13:10:30 +00:00
# include "DepthBuffer.h"
2013-11-27 10:08:48 +00:00
# include "N64.h"
2013-04-05 06:13:26 +00:00
# include "RSP.h"
# include "RDP.h"
2013-06-29 11:52:57 +00:00
# include "gDP.h"
2013-08-10 11:12:17 +00:00
# include "VI.h"
2013-04-05 06:13:26 +00:00
# include "Textures.h"
# include "Combiner.h"
2014-09-02 13:05:53 +00:00
# include "GLSLCombiner.h"
2013-04-05 06:13:26 +00:00
# include "Types.h"
2014-04-05 02:57:00 +00:00
# include "Config.h"
2013-06-01 13:10:30 +00:00
# include "Debug.h"
2015-01-30 13:59:52 +00:00
# include "PostProcessor.h"
2013-06-01 13:10:30 +00:00
2014-09-20 17:34:07 +00:00
using namespace std ;
2014-03-21 08:16:36 +00:00
# ifndef GLES2
const GLint monohromeInternalformat = GL_R8 ;
const GLenum monohromeformat = GL_RED ;
# else
const GLint monohromeInternalformat = GL_LUMINANCE ;
const GLenum monohromeformat = GL_LUMINANCE ;
# endif // GLES2
2014-04-10 14:44:07 +00:00
# ifndef GLES2
2013-09-05 16:24:34 +00:00
class FrameBufferToRDRAM
{
public :
FrameBufferToRDRAM ( ) :
2015-02-24 09:57:30 +00:00
m_FBO ( 0 ) , m_PBO ( 0 ) , m_pTexture ( NULL )
{ }
2013-09-05 16:24:34 +00:00
void Init ( ) ;
void Destroy ( ) ;
2015-02-24 09:57:30 +00:00
void CopyToRDRAM ( u32 _address ) ;
2013-09-05 16:24:34 +00:00
private :
2015-04-04 10:32:17 +00:00
void _copyWhite ( FrameBuffer * _pBuffer ) ;
2013-09-05 16:24:34 +00:00
struct RGBA {
u8 r , g , b , a ;
} ;
2013-09-07 16:28:20 +00:00
GLuint m_FBO ;
2015-02-24 09:57:30 +00:00
GLuint m_PBO ;
2013-09-07 16:28:20 +00:00
CachedTexture * m_pTexture ;
2013-09-05 16:24:34 +00:00
} ;
2013-11-12 08:41:19 +00:00
class DepthBufferToRDRAM
{
public :
DepthBufferToRDRAM ( ) :
2015-02-02 08:56:53 +00:00
m_FBO ( 0 ) , m_PBO ( 0 ) , m_pColorTexture ( NULL ) , m_pDepthTexture ( NULL ) , m_lastDList ( 0 )
2014-10-18 17:25:20 +00:00
{ }
2013-11-12 08:41:19 +00:00
void Init ( ) ;
void Destroy ( ) ;
2014-10-18 15:38:32 +00:00
bool CopyToRDRAM ( u32 address ) ;
2013-11-12 08:41:19 +00:00
private :
GLuint m_FBO ;
2014-10-18 17:25:20 +00:00
GLuint m_PBO ;
2015-02-02 08:56:53 +00:00
CachedTexture * m_pColorTexture ;
CachedTexture * m_pDepthTexture ;
2014-10-18 15:38:32 +00:00
u32 m_lastDList ;
2013-11-12 08:41:19 +00:00
} ;
2014-03-21 08:16:36 +00:00
# endif // GLES2
2013-11-12 08:41:19 +00:00
2013-09-07 16:31:04 +00:00
class RDRAMtoFrameBuffer
{
public :
RDRAMtoFrameBuffer ( ) : m_pTexture ( NULL ) , m_PBO ( 0 ) { }
void Init ( ) ;
void Destroy ( ) ;
2013-09-15 14:40:16 +00:00
void CopyFromRDRAM ( u32 _address , bool _bUseAlpha ) ;
2013-09-07 16:31:04 +00:00
private :
CachedTexture * m_pTexture ;
2014-03-21 08:16:36 +00:00
# ifndef GLES2
2013-09-07 16:31:04 +00:00
GLuint m_PBO ;
2014-03-21 08:16:36 +00:00
# else
GLubyte * m_PBO ;
# endif
2013-09-07 16:31:04 +00:00
} ;
2014-03-21 08:16:36 +00:00
# ifndef GLES2
2014-04-10 14:44:07 +00:00
FrameBufferToRDRAM g_fbToRDRAM ;
2013-11-12 08:41:19 +00:00
DepthBufferToRDRAM g_dbToRDRAM ;
2014-03-21 08:16:36 +00:00
# endif
2013-09-07 16:31:04 +00:00
RDRAMtoFrameBuffer g_RDRAMtoFB ;
2013-08-10 11:12:17 +00:00
2015-04-29 13:58:06 +00:00
FrameBuffer : : FrameBuffer ( ) : m_validityChecked ( 0 ) , m_cleared ( false ) , m_changed ( false ) , m_isDepthBuffer ( false ) ,
2015-04-30 09:34:59 +00:00
m_needHeightCorrection ( false ) , m_postProcessed ( false ) , m_pLoadTile ( NULL ) , m_pDepthBuffer ( NULL ) ,
2015-04-29 13:58:06 +00:00
m_pResolveTexture ( NULL ) , m_resolveFBO ( 0 ) , m_copiedToRdram ( false ) , m_resolved ( false )
2013-04-05 06:13:26 +00:00
{
2014-09-08 11:01:22 +00:00
m_pTexture = textureCache ( ) . addFrameBufferTexture ( ) ;
glGenFramebuffers ( 1 , & m_FBO ) ;
2013-04-05 06:13:26 +00:00
}
2014-09-08 11:01:22 +00:00
FrameBuffer : : FrameBuffer ( FrameBuffer & & _other ) :
m_startAddress ( _other . m_startAddress ) , m_endAddress ( _other . m_endAddress ) ,
m_size ( _other . m_size ) , m_width ( _other . m_width ) , m_height ( _other . m_height ) , m_fillcolor ( _other . m_fillcolor ) ,
2015-03-01 06:53:15 +00:00
m_scaleX ( _other . m_scaleX ) , m_scaleY ( _other . m_scaleY ) , m_cleared ( _other . m_cleared ) , m_changed ( _other . m_changed ) , m_cfb ( _other . m_cfb ) , m_isDepthBuffer ( _other . m_isDepthBuffer ) ,
2015-04-30 09:34:59 +00:00
m_copiedToRdram ( _other . m_copiedToRdram ) , m_needHeightCorrection ( _other . m_needHeightCorrection ) , m_postProcessed ( _other . m_postProcessed ) , m_validityChecked ( _other . m_validityChecked ) ,
2015-02-09 12:27:39 +00:00
m_FBO ( _other . m_FBO ) , m_pLoadTile ( _other . m_pLoadTile ) , m_pTexture ( _other . m_pTexture ) , m_pDepthBuffer ( _other . m_pDepthBuffer ) ,
2015-04-29 13:58:06 +00:00
m_pResolveTexture ( _other . m_pResolveTexture ) , m_resolveFBO ( _other . m_resolveFBO ) , m_resolved ( _other . m_resolved ) , m_RdramCopy ( _other . m_RdramCopy )
2013-04-05 06:13:26 +00:00
{
2014-09-08 11:01:22 +00:00
_other . m_FBO = 0 ;
_other . m_pTexture = NULL ;
_other . m_pLoadTile = NULL ;
_other . m_pDepthBuffer = NULL ;
2015-02-09 12:27:39 +00:00
_other . m_pResolveTexture = NULL ;
_other . m_resolveFBO = 0 ;
2015-04-29 13:58:06 +00:00
_other . m_RdramCopy . clear ( ) ;
2013-04-05 06:13:26 +00:00
}
2014-09-08 11:01:22 +00:00
FrameBuffer : : ~ FrameBuffer ( )
2013-04-05 06:13:26 +00:00
{
2014-09-08 11:01:22 +00:00
if ( m_FBO ! = 0 )
glDeleteFramebuffers ( 1 , & m_FBO ) ;
if ( m_pTexture ! = NULL )
textureCache ( ) . removeFrameBufferTexture ( m_pTexture ) ;
2015-02-09 12:27:39 +00:00
if ( m_resolveFBO ! = 0 )
glDeleteFramebuffers ( 1 , & m_resolveFBO ) ;
if ( m_pResolveTexture ! = NULL )
textureCache ( ) . removeFrameBufferTexture ( m_pResolveTexture ) ;
}
void FrameBuffer : : _initTexture ( u16 _format , u16 _size , CachedTexture * _pTexture )
{
2015-03-26 17:06:31 +00:00
_pTexture - > width = ( u32 ) ( m_width * m_scaleX ) ;
_pTexture - > height = ( u32 ) ( m_height * m_scaleY ) ;
2015-02-09 12:27:39 +00:00
_pTexture - > format = _format ;
_pTexture - > size = _size ;
_pTexture - > clampS = 1 ;
_pTexture - > clampT = 1 ;
_pTexture - > address = m_startAddress ;
_pTexture - > clampWidth = m_width ;
_pTexture - > clampHeight = m_height ;
_pTexture - > frameBufferTexture = TRUE ;
_pTexture - > maskS = 0 ;
_pTexture - > maskT = 0 ;
_pTexture - > mirrorS = 0 ;
_pTexture - > mirrorT = 0 ;
_pTexture - > realWidth = _pTexture - > width ;
_pTexture - > realHeight = _pTexture - > height ;
_pTexture - > textureBytes = _pTexture - > realWidth * _pTexture - > realHeight ;
if ( _size > G_IM_SIZ_8b )
_pTexture - > textureBytes * = 4 ;
textureCache ( ) . addFrameBufferTextureSize ( _pTexture - > textureBytes ) ;
}
void FrameBuffer : : _setAndAttachTexture ( u16 _size , CachedTexture * _pTexture )
{
glBindTexture ( GL_TEXTURE_2D , _pTexture - > glName ) ;
if ( _size > G_IM_SIZ_8b )
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , _pTexture - > realWidth , _pTexture - > realHeight , 0 , GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
else
glTexImage2D ( GL_TEXTURE_2D , 0 , monohromeInternalformat , _pTexture - > realWidth , _pTexture - > realHeight , 0 , monohromeformat , GL_UNSIGNED_BYTE , NULL ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , _pTexture - > glName , 0 ) ;
}
2015-05-06 13:16:46 +00:00
bool FrameBuffer : : _isMarioTennisScoreboard ( ) const
{
if ( ( config . generalEmulation . hacks & hack_scoreboard ) ! = 0 ) {
if ( VI . PAL )
return m_startAddress = = 0x13b480 | | m_startAddress = = 0x26a530 ;
else
return m_startAddress = = 0x13ba50 | | m_startAddress = = 0x264430 ;
}
return ( config . generalEmulation . hacks & hack_scoreboardJ ) ! = 0 & & ( m_startAddress = = 0x134080 | | m_startAddress = = 0x1332f8 ) ;
}
2015-02-09 12:27:39 +00:00
void FrameBuffer : : init ( u32 _address , u32 _endAddress , u16 _format , u16 _size , u16 _width , u16 _height , bool _cfb )
{
OGLVideo & ogl = video ( ) ;
m_startAddress = _address ;
m_endAddress = _endAddress ;
m_width = _width ;
m_height = _height ;
m_size = _size ;
m_scaleX = ogl . getScaleX ( ) ;
m_scaleY = ogl . getScaleY ( ) ;
m_fillcolor = 0 ;
m_cfb = _cfb ;
2015-03-19 14:17:35 +00:00
m_needHeightCorrection = _width ! = VI . width & & _width ! = * REG . VI_WIDTH ;
2015-03-17 13:36:17 +00:00
m_cleared = false ;
2015-02-09 12:27:39 +00:00
_initTexture ( _format , _size , m_pTexture ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , m_FBO ) ;
2015-05-04 14:32:58 +00:00
# ifdef GL_MULTISAMPLING_SUPPORT
2015-02-09 12:27:39 +00:00
if ( config . video . multisampling ! = 0 ) {
glBindTexture ( GL_TEXTURE_2D_MULTISAMPLE , m_pTexture - > glName ) ;
2015-05-04 14:32:58 +00:00
# if defined(GLES3_1)
2015-04-23 08:51:35 +00:00
if ( _size > G_IM_SIZ_8b )
glTexStorage2DMultisample ( GL_TEXTURE_2D_MULTISAMPLE , config . video . multisampling , GL_RGBA8 , m_pTexture - > realWidth , m_pTexture - > realHeight , false ) ;
else
glTexStorage2DMultisample ( GL_TEXTURE_2D_MULTISAMPLE , config . video . multisampling , monohromeInternalformat , m_pTexture - > realWidth , m_pTexture - > realHeight , false ) ;
2015-05-04 14:32:58 +00:00
# else
if ( _size > G_IM_SIZ_8b )
glTexImage2DMultisample ( GL_TEXTURE_2D_MULTISAMPLE , config . video . multisampling , GL_RGBA8 , m_pTexture - > realWidth , m_pTexture - > realHeight , false ) ;
else
glTexImage2DMultisample ( GL_TEXTURE_2D_MULTISAMPLE , config . video . multisampling , monohromeInternalformat , m_pTexture - > realWidth , m_pTexture - > realHeight , false ) ;
2015-04-23 08:51:35 +00:00
# endif
2015-05-04 14:32:58 +00:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D_MULTISAMPLE , m_pTexture - > glName , 0 ) ;
2015-02-09 12:27:39 +00:00
m_pResolveTexture = textureCache ( ) . addFrameBufferTexture ( ) ;
_initTexture ( _format , _size , m_pResolveTexture ) ;
glGenFramebuffers ( 1 , & m_resolveFBO ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , m_resolveFBO ) ;
_setAndAttachTexture ( _size , m_pResolveTexture ) ;
assert ( checkFBO ( ) ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , m_FBO ) ;
} else
2015-05-04 14:32:58 +00:00
# endif // GL_MULTISAMPLING_SUPPORT
2015-02-09 12:27:39 +00:00
_setAndAttachTexture ( _size , m_pTexture ) ;
}
2015-03-11 10:59:42 +00:00
void FrameBuffer : : reinit ( u16 _height )
{
const u16 format = m_pTexture - > format ;
const u32 endAddress = m_startAddress + ( ( m_width * ( _height - 1 ) ) < < m_size > > 1 ) - 1 ;
if ( m_pTexture ! = NULL )
textureCache ( ) . removeFrameBufferTexture ( m_pTexture ) ;
if ( m_resolveFBO ! = 0 )
glDeleteFramebuffers ( 1 , & m_resolveFBO ) ;
if ( m_pResolveTexture ! = NULL )
textureCache ( ) . removeFrameBufferTexture ( m_pResolveTexture ) ;
m_pTexture = textureCache ( ) . addFrameBufferTexture ( ) ;
init ( m_startAddress , endAddress , format , m_size , m_width , _height , m_cfb ) ;
}
2015-04-29 13:58:06 +00:00
inline
u32 _cutHeight ( u32 _address , u32 _height , u32 _stride )
{
if ( _address + _stride * _height > RDRAMSize )
_height = ( RDRAMSize - _address ) / _stride ;
return _height ;
}
void FrameBuffer : : copyRdram ( )
{
const u32 stride = m_width < < m_size > > 1 ;
const u32 height = _cutHeight ( m_startAddress , m_height , stride ) ;
const u32 dataSize = stride * height ;
// Auxiliary frame buffer
if ( m_width ! = VI . width ) {
if ( config . frameBufferEmulation . validityCheckMethod = = Config : : vcFill ) {
gDPFillRDRAM ( m_startAddress , 0 , 0 , m_width , height , m_width , m_size , m_fillcolor , false ) ;
return ;
}
if ( config . frameBufferEmulation . validityCheckMethod = = Config : : vcFingerprint ) {
// Write small amount of data to the start of the buffer.
// This is necessary for auxilary buffers: game can restore content of RDRAM when buffer is not needed anymore
// Thus content of RDRAM on moment of buffer creation will be the same as when buffer becomes obsolete.
// Validity check will see that the RDRAM is the same and thus the buffer is valid, which is false.
// It can be enough to write data just little more than treshold level, but more safe to write twice as much in case that some values in buffer match our fingerprint.
const u32 twoPercent = dataSize / 200 ;
u32 start = m_startAddress > > 2 ;
u32 * pData = ( u32 * ) RDRAM ;
for ( u32 i = 0 ; i < twoPercent ; + + i )
pData [ start + + ] = m_startAddress ;
}
}
m_RdramCopy . resize ( dataSize ) ;
memcpy ( m_RdramCopy . data ( ) , RDRAM + m_startAddress , dataSize ) ;
}
bool FrameBuffer : : isValid ( ) const
{
if ( m_validityChecked = = RSP . DList )
return true ; // Already checked
const u32 * const pData = ( const u32 * ) RDRAM ;
if ( m_cleared ) {
const u32 color = m_fillcolor & 0xFFFEFFFE ;
const u32 start = m_startAddress > > 2 ;
const u32 end = m_endAddress > > 2 ;
u32 wrongPixels = 0 ;
for ( u32 i = start ; i < end ; + + i ) {
if ( ( pData [ i ] & 0xFFFEFFFE ) ! = color )
+ + wrongPixels ;
}
return wrongPixels < ( m_endAddress - m_startAddress ) / 400 ; // treshold level 1% of dwords
} else if ( ! m_RdramCopy . empty ( ) ) {
const u32 * const pCopy = ( const u32 * ) m_RdramCopy . data ( ) ;
const u32 size = m_RdramCopy . size ( ) ;
const u32 size_dwords = size > > 2 ;
u32 start = m_startAddress > > 2 ;
u32 wrongPixels = 0 ;
for ( u32 i = 0 ; i < size_dwords ; + + i ) {
if ( ( pData [ start + + ] & 0xFFFEFFFE ) ! = ( pCopy [ i ] & 0xFFFEFFFE ) )
+ + wrongPixels ;
}
return wrongPixels < size / 400 ; // treshold level 1% of dwords
}
return true ; // No data to decide
}
2015-03-11 10:59:42 +00:00
2015-02-09 12:27:39 +00:00
void FrameBuffer : : resolveMultisampledTexture ( )
{
if ( m_resolved )
return ;
2015-04-03 14:58:45 +00:00
glScissor ( 0 , 0 , m_pTexture - > realWidth , m_pTexture - > realHeight ) ;
2015-02-09 12:27:39 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , m_FBO ) ;
glReadBuffer ( GL_COLOR_ATTACHMENT0 ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , m_resolveFBO ) ;
glBlitFramebuffer (
0 , 0 , m_pTexture - > realWidth , m_pTexture - > realHeight ,
0 , 0 , m_pResolveTexture - > realWidth , m_pResolveTexture - > realHeight ,
GL_COLOR_BUFFER_BIT , GL_NEAREST
) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , frameBufferList ( ) . getCurrent ( ) - > m_FBO ) ;
2015-04-03 14:58:45 +00:00
gDP . changed | = CHANGED_SCISSOR ;
2015-02-09 12:27:39 +00:00
m_resolved = true ;
}
CachedTexture * FrameBuffer : : getTexture ( )
{
if ( config . video . multisampling = = 0 )
return m_pTexture ;
if ( m_resolved )
return m_pResolveTexture ;
resolveMultisampledTexture ( ) ;
return m_pResolveTexture ;
2013-04-05 06:13:26 +00:00
}
2015-03-31 12:44:41 +00:00
FrameBufferList & FrameBufferList : : get ( )
{
static FrameBufferList frameBufferList ;
return frameBufferList ;
}
2014-09-08 11:01:22 +00:00
void FrameBufferList : : init ( )
2013-04-05 06:13:26 +00:00
{
2014-09-08 11:01:22 +00:00
m_pCurrent = NULL ;
}
2013-04-05 06:13:26 +00:00
2014-09-08 11:01:22 +00:00
void FrameBufferList : : destroy ( ) {
m_list . clear ( ) ;
m_pCurrent = NULL ;
2013-04-05 06:13:26 +00:00
}
2015-03-01 11:52:59 +00:00
void FrameBufferList : : setBufferChanged ( )
{
gDP . colorImage . changed = TRUE ;
2015-03-09 11:17:20 +00:00
if ( m_pCurrent ! = NULL ) {
2015-03-01 11:52:59 +00:00
m_pCurrent - > m_changed = true ;
2015-04-29 13:58:06 +00:00
m_pCurrent - > m_copiedToRdram = false ;
m_pCurrent - > m_validityChecked = 0 ;
2015-03-09 11:17:20 +00:00
}
2015-03-01 11:52:59 +00:00
}
2015-03-01 06:53:15 +00:00
void FrameBufferList : : correctHeight ( )
{
if ( m_pCurrent = = NULL )
return ;
if ( m_pCurrent - > m_changed ) {
m_pCurrent - > m_needHeightCorrection = false ;
return ;
}
if ( m_pCurrent - > m_needHeightCorrection & & m_pCurrent - > m_width = = gDP . scissor . lrx ) {
2015-03-11 10:59:42 +00:00
if ( m_pCurrent - > m_height < ( u32 ) gDP . scissor . lry )
m_pCurrent - > reinit ( ( u32 ) gDP . scissor . lry ) ;
else
m_pCurrent - > m_height = ( u32 ) gDP . scissor . lry ;
2015-03-15 05:31:43 +00:00
2015-05-06 13:16:46 +00:00
if ( m_pCurrent - > _isMarioTennisScoreboard ( ) )
2015-03-15 05:31:43 +00:00
g_RDRAMtoFB . CopyFromRDRAM ( m_pCurrent - > m_startAddress + 4 , false ) ;
2015-03-01 06:53:15 +00:00
m_pCurrent - > m_needHeightCorrection = false ;
gSP . changed | = CHANGED_VIEWPORT ;
}
}
2015-03-01 11:52:59 +00:00
void FrameBufferList : : clearBuffersChanged ( )
{
gDP . colorImage . changed = FALSE ;
2015-03-30 12:06:21 +00:00
FrameBuffer * pBuffer = frameBufferList ( ) . findBuffer ( * REG . VI_ORIGIN ) ;
if ( pBuffer ! = NULL )
pBuffer - > m_changed = false ;
2015-03-01 11:52:59 +00:00
}
2014-10-22 07:49:55 +00:00
FrameBuffer * FrameBufferList : : findBuffer ( u32 _startAddress )
2013-04-05 06:13:26 +00:00
{
2014-09-08 11:01:22 +00:00
for ( FrameBuffers : : iterator iter = m_list . begin ( ) ; iter ! = m_list . end ( ) ; + + iter )
2014-10-22 07:49:55 +00:00
if ( iter - > m_startAddress < = _startAddress & & iter - > m_endAddress > = _startAddress ) // [ { ]
return & ( * iter ) ;
return NULL ;
}
FrameBuffer * FrameBufferList : : _findBuffer ( u32 _startAddress , u32 _endAddress , u32 _width )
{
if ( m_list . empty ( ) )
return NULL ;
FrameBuffers : : iterator iter = m_list . end ( ) ;
do {
- - iter ;
if ( ( iter - > m_startAddress < = _startAddress & & iter - > m_endAddress > = _startAddress ) | | // [ { ]
( _startAddress < = iter - > m_startAddress & & _endAddress > = iter - > m_startAddress ) ) { // { [ }
if ( _startAddress ! = iter - > m_startAddress | | _width ! = iter - > m_width ) {
m_list . erase ( iter ) ;
return _findBuffer ( _startAddress , _endAddress , _width ) ;
}
return & ( * iter ) ;
}
} while ( iter ! = m_list . begin ( ) ) ;
2014-09-08 11:01:22 +00:00
return NULL ;
2013-04-05 06:13:26 +00:00
}
2014-09-08 11:01:22 +00:00
FrameBuffer * FrameBufferList : : findTmpBuffer ( u32 _address )
2013-04-05 06:13:26 +00:00
{
2014-09-08 11:01:22 +00:00
for ( FrameBuffers : : iterator iter = m_list . begin ( ) ; iter ! = m_list . end ( ) ; + + iter )
if ( iter - > m_startAddress > _address | | iter - > m_endAddress < _address )
return & ( * iter ) ;
return NULL ;
2013-04-05 06:13:26 +00:00
}
2014-09-28 06:09:03 +00:00
void FrameBufferList : : saveBuffer ( u32 _address , u16 _format , u16 _size , u16 _width , u16 _height , bool _cfb )
2013-04-05 06:13:26 +00:00
{
2015-03-11 14:56:16 +00:00
if ( VI . width = = 0 | | _height = = 0 )
2014-09-27 06:17:01 +00:00
return ;
2015-03-15 05:31:43 +00:00
2014-09-21 12:15:22 +00:00
OGLVideo & ogl = video ( ) ;
2015-03-19 14:42:09 +00:00
if ( m_pCurrent ! = NULL ) {
if ( gDP . colorImage . height > 0 ) {
if ( m_pCurrent - > m_width = = VI . width )
gDP . colorImage . height = min ( gDP . colorImage . height , VI . height ) ;
m_pCurrent - > m_endAddress = min ( RDRAMSize , m_pCurrent - > m_startAddress + ( ( ( m_pCurrent - > m_width * gDP . colorImage . height ) < < m_pCurrent - > m_size > > 1 ) - 1 ) ) ;
2015-05-06 13:16:46 +00:00
if ( ! config . frameBufferEmulation . copyFromRDRAM & & ! m_pCurrent - > _isMarioTennisScoreboard ( ) & & ! m_pCurrent - > m_isDepthBuffer & & ! m_pCurrent - > m_copiedToRdram & & ! m_pCurrent - > m_cfb & & ! m_pCurrent - > m_cleared & & m_pCurrent - > m_RdramCopy . empty ( ) & & gDP . colorImage . height > 1 ) {
2015-04-29 13:58:06 +00:00
m_pCurrent - > copyRdram ( ) ;
2015-04-08 13:11:32 +00:00
}
2015-03-19 14:42:09 +00:00
}
2015-03-11 14:59:06 +00:00
m_pCurrent = _findBuffer ( m_pCurrent - > m_startAddress , m_pCurrent - > m_endAddress , m_pCurrent - > m_width ) ;
2013-08-10 11:10:44 +00:00
}
2015-02-18 06:09:39 +00:00
const u32 endAddress = _address + ( ( _width * ( _height - 1 ) ) < < _size > > 1 ) - 1 ;
2014-10-22 07:49:55 +00:00
if ( m_pCurrent = = NULL | | m_pCurrent - > m_startAddress ! = _address | | m_pCurrent - > m_width ! = _width )
2015-03-11 14:59:06 +00:00
m_pCurrent = findBuffer ( _address ) ;
2014-09-08 11:01:22 +00:00
if ( m_pCurrent ! = NULL ) {
if ( ( m_pCurrent - > m_startAddress ! = _address ) | |
( m_pCurrent - > m_width ! = _width ) | |
2013-09-04 02:15:05 +00:00
//(current->height != height) ||
//(current->size != size) || // TODO FIX ME
2014-09-21 12:15:22 +00:00
( m_pCurrent - > m_scaleX ! = ogl . getScaleX ( ) ) | |
( m_pCurrent - > m_scaleY ! = ogl . getScaleY ( ) ) )
2013-04-05 06:13:26 +00:00
{
2014-09-08 11:01:22 +00:00
removeBuffer ( m_pCurrent - > m_startAddress ) ;
m_pCurrent = NULL ;
2013-09-05 15:53:49 +00:00
} else {
2015-02-09 12:27:39 +00:00
m_pCurrent - > m_resolved = false ;
2014-09-08 11:01:22 +00:00
glBindFramebuffer ( GL_FRAMEBUFFER , m_pCurrent - > m_FBO ) ;
if ( m_pCurrent - > m_size ! = _size ) {
2013-09-05 15:53:49 +00:00
f32 fillColor [ 4 ] ;
gDPGetFillColor ( fillColor ) ;
2014-09-21 12:15:22 +00:00
ogl . getRender ( ) . clearColorBuffer ( fillColor ) ;
2014-09-08 11:01:22 +00:00
m_pCurrent - > m_size = _size ;
m_pCurrent - > m_pTexture - > format = _format ;
m_pCurrent - > m_pTexture - > size = _size ;
2015-02-21 14:20:32 +00:00
if ( m_pCurrent - > m_pResolveTexture ! = NULL ) {
m_pCurrent - > m_pResolveTexture - > format = _format ;
m_pCurrent - > m_pResolveTexture - > size = _size ;
}
2015-04-29 13:58:06 +00:00
if ( m_pCurrent - > m_copiedToRdram )
m_pCurrent - > copyRdram ( ) ;
2013-09-05 15:53:49 +00:00
}
2013-04-05 06:13:26 +00:00
}
2013-09-05 15:53:49 +00:00
}
2014-09-08 11:01:22 +00:00
const bool bNew = m_pCurrent = = NULL ;
2013-10-19 13:32:39 +00:00
if ( bNew ) {
2013-09-05 15:53:49 +00:00
// Wasn't found or removed, create a new one
2014-09-08 11:01:22 +00:00
m_list . emplace_front ( ) ;
FrameBuffer & buffer = m_list . front ( ) ;
2015-02-09 12:27:39 +00:00
buffer . init ( _address , endAddress , _format , _size , _width , _height , _cfb ) ;
2014-09-08 11:01:22 +00:00
m_pCurrent = & buffer ;
2015-04-27 10:40:25 +00:00
2015-05-06 13:16:46 +00:00
if ( m_pCurrent - > _isMarioTennisScoreboard ( ) | | ( ( config . generalEmulation . hacks & hack_legoRacers ) ! = 0 & & _width = = VI . width ) )
2015-04-27 10:40:25 +00:00
g_RDRAMtoFB . CopyFromRDRAM ( m_pCurrent - > m_startAddress + 4 , false ) ;
2013-06-04 16:05:09 +00:00
}
2013-06-01 13:10:30 +00:00
2015-04-08 17:06:17 +00:00
if ( _address = = gDP . depthImageAddress )
depthBufferList ( ) . saveBuffer ( _address ) ;
else
attachDepthBuffer ( ) ;
2013-06-01 13:10:30 +00:00
# ifdef DEBUG
DebugMsg ( DEBUG_HIGH | DEBUG_HANDLED , " FrameBuffer_SaveBuffer( 0x%08X ); depth buffer is 0x%08X \n " ,
address , ( depthBuffer . top ! = NULL & & depthBuffer . top - > renderbuf > 0 ) ? depthBuffer . top - > address : 0
) ;
# endif
2015-03-15 05:31:43 +00:00
2015-03-09 11:17:52 +00:00
m_pCurrent - > m_isDepthBuffer = _address = = gDP . depthImageAddress ;
2015-03-09 12:17:45 +00:00
m_pCurrent - > m_isPauseScreen = m_pCurrent - > m_isOBScreen = false ;
2015-04-30 09:34:59 +00:00
m_pCurrent - > m_postProcessed = false ;
2013-04-05 06:13:26 +00:00
gSP . changed | = CHANGED_TEXTURE ;
}
2014-09-08 11:01:22 +00:00
void FrameBufferList : : removeBuffer ( u32 _address )
{
for ( FrameBuffers : : iterator iter = m_list . begin ( ) ; iter ! = m_list . end ( ) ; + + iter )
if ( iter - > m_startAddress = = _address ) {
2015-04-02 09:43:57 +00:00
if ( & ( * iter ) = = m_pCurrent )
2015-02-19 07:01:31 +00:00
m_pCurrent = NULL ;
2014-09-08 11:01:22 +00:00
m_list . erase ( iter ) ;
return ;
}
}
2015-03-11 14:46:00 +00:00
void FrameBufferList : : removeBuffers ( u32 _width )
2015-03-11 11:33:47 +00:00
{
m_pCurrent = NULL ;
for ( FrameBuffers : : iterator iter = m_list . begin ( ) ; iter ! = m_list . end ( ) ; + + iter ) {
2015-03-11 14:46:00 +00:00
while ( iter - > m_width = = _width ) {
2015-04-02 09:43:57 +00:00
if ( & ( * iter ) = = m_pCurrent )
m_pCurrent = NULL ;
2015-03-11 11:33:47 +00:00
iter = m_list . erase ( iter ) ;
if ( iter = = m_list . end ( ) )
return ;
}
}
}
2014-09-08 11:01:22 +00:00
void FrameBufferList : : attachDepthBuffer ( )
2013-10-30 06:07:24 +00:00
{
2015-01-27 16:00:06 +00:00
if ( m_pCurrent = = NULL )
return ;
2014-09-08 11:00:13 +00:00
DepthBuffer * pDepthBuffer = depthBufferList ( ) . getCurrent ( ) ;
2015-01-27 16:00:06 +00:00
if ( m_pCurrent - > m_FBO > 0 & & pDepthBuffer ! = NULL ) {
pDepthBuffer - > initDepthImageTexture ( m_pCurrent ) ;
pDepthBuffer - > initDepthBufferTexture ( m_pCurrent ) ;
2015-04-11 17:17:38 +00:00
if ( pDepthBuffer - > m_pDepthBufferTexture - > realWidth > = m_pCurrent - > m_pTexture - > realWidth ) {
m_pCurrent - > m_pDepthBuffer = pDepthBuffer ;
pDepthBuffer - > setDepthAttachment ( GL_DRAW_FRAMEBUFFER ) ;
if ( video ( ) . getRender ( ) . isImageTexturesSupported ( ) & & config . frameBufferEmulation . N64DepthCompare ! = 0 )
pDepthBuffer - > bindDepthImageTexture ( ) ;
} else
m_pCurrent - > m_pDepthBuffer = NULL ;
2015-01-27 16:00:06 +00:00
} else
2014-09-08 11:01:22 +00:00
m_pCurrent - > m_pDepthBuffer = NULL ;
2015-01-27 16:00:06 +00:00
2014-04-08 11:53:25 +00:00
# ifndef GLES2
2015-01-27 16:00:06 +00:00
GLuint attachments [ 1 ] = { GL_COLOR_ATTACHMENT0 } ;
glDrawBuffers ( 1 , attachments ) ;
2014-04-08 11:53:25 +00:00
# endif
2015-01-27 16:00:06 +00:00
assert ( checkFBO ( ) ) ;
2013-10-30 06:07:24 +00:00
}
2013-06-01 13:13:04 +00:00
2014-09-08 11:01:22 +00:00
void FrameBuffer_Init ( )
{
frameBufferList ( ) . init ( ) ;
2015-05-04 08:46:14 +00:00
if ( config . frameBufferEmulation . enable ! = 0 ) {
2014-04-10 14:44:07 +00:00
# ifndef GLES2
2014-09-08 11:01:22 +00:00
g_fbToRDRAM . Init ( ) ;
g_dbToRDRAM . Init ( ) ;
# endif
g_RDRAMtoFB . Init ( ) ;
2015-05-04 08:46:14 +00:00
}
2014-09-08 11:01:22 +00:00
}
void FrameBuffer_Destroy ( )
{
2015-05-04 08:46:14 +00:00
if ( config . frameBufferEmulation . enable ! = 0 ) {
2014-09-08 11:01:22 +00:00
g_RDRAMtoFB . Destroy ( ) ;
# ifndef GLES2
g_dbToRDRAM . Destroy ( ) ;
g_fbToRDRAM . Destroy ( ) ;
# endif
2015-05-04 08:46:14 +00:00
}
2014-09-08 11:01:22 +00:00
frameBufferList ( ) . destroy ( ) ;
}
# ifndef GLES2
void FrameBufferList : : renderBuffer ( u32 _address )
2013-06-01 13:13:04 +00:00
{
2014-10-10 10:22:10 +00:00
static s32 vStartPrev = 0 ;
2014-09-26 12:19:23 +00:00
2015-04-13 16:37:11 +00:00
if ( VI . width = = 0 | | * REG . VI_WIDTH = = 0 | | * REG . VI_H_START = = 0 ) // H width is zero. Don't draw
2013-09-29 15:02:50 +00:00
return ;
2014-09-27 15:27:32 +00:00
2014-10-22 07:49:55 +00:00
FrameBuffer * pBuffer = findBuffer ( _address ) ;
2014-09-08 11:01:22 +00:00
if ( pBuffer = = NULL )
2013-09-04 02:15:05 +00:00
return ;
2014-09-27 15:27:32 +00:00
2014-09-21 12:15:22 +00:00
OGLVideo & ogl = video ( ) ;
2013-09-29 15:02:50 +00:00
GLint srcY0 , srcY1 , dstY0 , dstY1 ;
2015-02-18 12:59:20 +00:00
GLint X0 , X1 , Xwidth ;
2014-10-10 10:22:10 +00:00
GLint srcPartHeight = 0 ;
GLint dstPartHeight = 0 ;
const f32 yScale = _FIXED2FLOAT ( _SHIFTR ( * REG . VI_Y_SCALE , 0 , 12 ) , 10 ) ;
s32 vEnd = _SHIFTR ( * REG . VI_V_START , 0 , 10 ) ;
s32 vStart = _SHIFTR ( * REG . VI_V_START , 16 , 10 ) ;
2015-02-18 12:59:20 +00:00
const s32 hEnd = _SHIFTR ( * REG . VI_H_START , 0 , 10 ) ;
const s32 hStart = _SHIFTR ( * REG . VI_H_START , 16 , 10 ) ;
2014-10-10 10:22:10 +00:00
const s32 vSync = ( * REG . VI_V_SYNC ) & 0x03FF ;
const bool interlaced = ( * REG . VI_STATUS & 0x40 ) ! = 0 ;
const bool isPAL = vSync > 550 ;
const s32 vShift = ( isPAL ? 47 : 37 ) ;
dstY0 = vStart - vShift ;
dstY0 > > = 1 ;
dstY0 & = - ( dstY0 > = 0 ) ;
vStart > > = 1 ;
vEnd > > = 1 ;
const u32 vFullHeight = isPAL ? 288 : 240 ;
const u32 vCurrentHeight = vEnd - vStart ;
const float dstScaleY = ( float ) ogl . getHeight ( ) / float ( vFullHeight ) ;
2014-09-26 12:19:23 +00:00
bool isLowerField = false ;
2014-10-13 12:33:19 +00:00
if ( interlaced )
2014-09-28 06:44:03 +00:00
isLowerField = vStart > vStartPrev ;
2014-09-26 12:19:23 +00:00
vStartPrev = vStart ;
2014-09-08 11:01:22 +00:00
srcY0 = ( ( _address - pBuffer - > m_startAddress ) < < 1 > > pBuffer - > m_size ) / ( * REG . VI_WIDTH ) ;
2014-11-29 13:01:27 +00:00
if ( isLowerField ) {
if ( srcY0 > 0 )
2014-09-26 12:19:23 +00:00
- - srcY0 ;
2014-11-29 13:01:27 +00:00
if ( dstY0 > 0 )
- - dstY0 ;
}
2014-09-26 12:19:23 +00:00
2014-10-10 10:22:10 +00:00
if ( srcY0 + vCurrentHeight > vFullHeight ) {
dstPartHeight = srcY0 ;
srcY0 = ( GLint ) ( srcY0 * yScale ) ;
srcPartHeight = srcY0 ;
srcY1 = VI . real_height ;
dstY1 = dstY0 + vCurrentHeight - dstPartHeight ;
2014-09-27 15:27:32 +00:00
} else {
2014-10-10 10:22:10 +00:00
dstY0 + = srcY0 ;
dstY1 = dstY0 + vCurrentHeight ;
srcY0 = ( GLint ) ( srcY0 * yScale ) ;
srcY1 = srcY0 + VI . real_height ;
2013-09-29 15:02:50 +00:00
}
2015-02-18 12:59:20 +00:00
const f32 scaleX = _FIXED2FLOAT ( _SHIFTR ( * REG . VI_X_SCALE , 0 , 12 ) , 10 ) ;
2015-02-21 14:44:32 +00:00
const s32 h0 = ( isPAL ? 128 : 108 ) ;
const s32 hx0 = max ( 0 , hStart - h0 ) ;
const s32 hx1 = max ( 0 , h0 + 640 - hEnd ) ;
X0 = ( GLint ) ( hx0 * scaleX * ogl . getScaleX ( ) ) ;
Xwidth = ( GLint ) ( ( min ( ( f32 ) VI . width , ( hEnd - hStart ) * scaleX ) ) * ogl . getScaleX ( ) ) ;
X1 = ogl . getWidth ( ) - ( GLint ) ( hx1 * scaleX * ogl . getScaleX ( ) ) ;
2015-02-09 05:36:20 +00:00
2015-04-03 05:36:31 +00:00
const float srcScaleY = ogl . getScaleY ( ) ;
const GLint hOffset = ( ogl . getScreenWidth ( ) - ogl . getWidth ( ) ) / 2 ;
const GLint vOffset = ( ogl . getScreenHeight ( ) - ogl . getHeight ( ) ) / 2 + ogl . getHeightOffset ( ) ;
CachedTexture * pBufferTexture = pBuffer - > m_pTexture ;
GLint srcCoord [ 4 ] = { 0 , ( GLint ) ( srcY0 * srcScaleY ) , Xwidth , min ( ( GLint ) ( srcY1 * srcScaleY ) , ( GLint ) pBufferTexture - > realHeight ) } ;
if ( srcCoord [ 2 ] > pBufferTexture - > realWidth | | srcCoord [ 3 ] > pBufferTexture - > realHeight ) {
removeBuffer ( pBuffer - > m_startAddress ) ;
return ;
}
GLint dstCoord [ 4 ] = { X0 + hOffset , vOffset + ( GLint ) ( dstY0 * dstScaleY ) , hOffset + X1 , vOffset + ( GLint ) ( dstY1 * dstScaleY ) } ;
2015-04-30 09:13:40 +00:00
ogl . getRender ( ) . updateScissor ( pBuffer ) ;
2015-01-31 07:14:13 +00:00
PostProcessor : : get ( ) . process ( pBuffer ) ;
2014-06-09 04:26:43 +00:00
// glDisable(GL_SCISSOR_TEST) does not affect glBlitFramebuffer, at least on AMD
2015-04-03 05:36:31 +00:00
glScissor ( 0 , 0 , ogl . getScreenWidth ( ) , ogl . getScreenHeight ( ) + ogl . getHeightOffset ( ) ) ;
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
2014-03-21 08:16:36 +00:00
//glDrawBuffer( GL_BACK );
2015-04-03 05:36:31 +00:00
float clearColor [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
2014-09-21 12:15:22 +00:00
ogl . getRender ( ) . clearColorBuffer ( clearColor ) ;
2015-02-09 12:27:39 +00:00
GLenum filter = GL_LINEAR ;
if ( config . video . multisampling ! = 0 ) {
2015-02-21 14:44:32 +00:00
if ( X0 > 0 | | dstPartHeight > 0 | |
2015-02-09 12:27:39 +00:00
( srcCoord [ 2 ] - srcCoord [ 0 ] ) ! = ( dstCoord [ 2 ] - dstCoord [ 0 ] ) | |
( srcCoord [ 3 ] - srcCoord [ 1 ] ) ! = ( dstCoord [ 3 ] - dstCoord [ 1 ] ) ) {
pBuffer - > resolveMultisampledTexture ( ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , pBuffer - > m_resolveFBO ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
2015-04-03 05:36:31 +00:00
} else {
glBindFramebuffer ( GL_READ_FRAMEBUFFER , pBuffer - > m_FBO ) ;
2015-02-09 12:27:39 +00:00
filter = GL_NEAREST ;
2015-04-03 05:36:31 +00:00
}
} else
glBindFramebuffer ( GL_READ_FRAMEBUFFER , pBuffer - > m_FBO ) ;
2015-02-09 05:36:20 +00:00
2014-03-21 09:38:39 +00:00
glBlitFramebuffer (
2015-02-09 12:27:39 +00:00
srcCoord [ 0 ] , srcCoord [ 1 ] , srcCoord [ 2 ] , srcCoord [ 3 ] ,
dstCoord [ 0 ] , dstCoord [ 1 ] , dstCoord [ 2 ] , dstCoord [ 3 ] ,
2015-02-09 05:36:20 +00:00
GL_COLOR_BUFFER_BIT , filter
2013-09-04 02:15:05 +00:00
) ;
2014-09-26 12:19:23 +00:00
2014-10-10 10:22:10 +00:00
if ( dstPartHeight > 0 ) {
2013-09-29 15:02:50 +00:00
const u32 size = * REG . VI_STATUS & 3 ;
2014-09-08 11:01:22 +00:00
pBuffer = findBuffer ( _address + ( ( ( * REG . VI_WIDTH ) * VI . height ) < < size > > 1 ) ) ;
if ( pBuffer ! = NULL ) {
2013-09-29 15:02:50 +00:00
srcY0 = 0 ;
2014-10-10 10:22:10 +00:00
srcY1 = srcPartHeight ;
2013-09-29 15:02:50 +00:00
dstY0 = dstY1 ;
2014-10-10 10:22:10 +00:00
dstY1 = dstY0 + dstPartHeight ;
2014-09-08 11:01:22 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , pBuffer - > m_FBO ) ;
2014-03-21 09:38:39 +00:00
glBlitFramebuffer (
2015-03-17 12:03:45 +00:00
0 , ( GLint ) ( srcY0 * srcScaleY ) , ogl . getWidth ( ) , min ( ( GLint ) ( srcY1 * srcScaleY ) , ( GLint ) pBuffer - > m_pTexture - > realHeight ) ,
2014-10-10 10:22:10 +00:00
hOffset , vOffset + ( GLint ) ( dstY0 * dstScaleY ) , hOffset + ogl . getWidth ( ) , vOffset + ( GLint ) ( dstY1 * dstScaleY ) ,
2015-02-09 05:36:20 +00:00
GL_COLOR_BUFFER_BIT , filter
2013-09-29 15:02:50 +00:00
) ;
}
}
2014-09-26 12:19:23 +00:00
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
2015-03-11 11:34:39 +00:00
if ( m_pCurrent ! = NULL )
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , m_pCurrent - > m_FBO ) ;
2014-09-21 12:15:22 +00:00
ogl . swapBuffers ( ) ;
2014-06-09 04:26:43 +00:00
gDP . changed | = CHANGED_SCISSOR ;
2013-06-01 13:13:04 +00:00
}
# else
2014-09-08 11:01:22 +00:00
void FrameBufferList : : renderBuffer ( u32 _address )
2013-04-05 06:13:26 +00:00
{
2014-10-03 09:51:12 +00:00
if ( VI . width = = 0 ) // H width is zero. Don't draw
2014-04-10 15:44:05 +00:00
return ;
2014-09-08 11:01:22 +00:00
FrameBuffer * pBuffer = findBuffer ( _address ) ;
if ( pBuffer = = NULL )
2014-04-10 15:44:05 +00:00
return ;
2013-06-01 13:10:30 +00:00
2014-09-08 11:01:22 +00:00
CombinerInfo : : get ( ) . setCombine ( EncodeCombineMode ( 0 , 0 , 0 , TEXEL0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , TEXEL0 , 0 , 0 , 0 , 1 ) ) ;
2014-04-10 15:44:05 +00:00
glDisable ( GL_BLEND ) ;
2014-05-14 09:23:49 +00:00
glDisable ( GL_SCISSOR_TEST ) ;
glDisable ( GL_DEPTH_TEST ) ;
2014-04-10 15:44:05 +00:00
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_POLYGON_OFFSET_FILL ) ;
gSP . changed = gDP . changed = 0 ;
2014-09-08 11:01:22 +00:00
const u32 width = pBuffer - > m_width ;
const u32 height = pBuffer - > m_height ;
2014-04-10 15:44:05 +00:00
2014-09-21 12:15:22 +00:00
OGLVideo & ogl = video ( ) ;
pBuffer - > m_pTexture - > scaleS = ogl . getScaleX ( ) / ( float ) pBuffer - > m_pTexture - > realWidth ;
pBuffer - > m_pTexture - > scaleT = ogl . getScaleY ( ) / ( float ) pBuffer - > m_pTexture - > realHeight ;
2014-09-08 11:01:22 +00:00
pBuffer - > m_pTexture - > shiftScaleS = 1.0f ;
pBuffer - > m_pTexture - > shiftScaleT = 1.0f ;
pBuffer - > m_pTexture - > offsetS = 0 ;
pBuffer - > m_pTexture - > offsetT = ( float ) height ;
textureCache ( ) . activateTexture ( 0 , pBuffer - > m_pTexture ) ;
2014-04-10 15:44:05 +00:00
gSP . textureTile [ 0 ] - > fuls = gSP . textureTile [ 0 ] - > fult = 0.0f ;
2014-09-08 11:01:22 +00:00
currentCombiner ( ) - > updateTextureInfo ( true ) ;
2014-04-10 15:44:05 +00:00
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2014-09-26 12:20:19 +00:00
m_drawBuffer = GL_BACK ;
2014-11-06 08:37:04 +00:00
OGLRender : : TexturedRectParams params ( 0.0f , 0.0f , width , height , 0.0f , 0.0f , width - 1.0f , height - 1.0f , false ) ;
ogl . getRender ( ) . drawTexturedRect ( params ) ;
2014-09-21 12:15:22 +00:00
ogl . swapBuffers ( ) ;
2014-09-26 12:20:19 +00:00
m_drawBuffer = GL_FRAMEBUFFER ;
2014-06-09 04:26:43 +00:00
glEnable ( GL_SCISSOR_TEST ) ;
2014-09-08 11:01:22 +00:00
glBindFramebuffer ( GL_FRAMEBUFFER , m_pCurrent - > m_FBO ) ;
2014-04-10 15:44:05 +00:00
gSP . changed | = CHANGED_TEXTURE | CHANGED_VIEWPORT ;
gDP . changed | = CHANGED_COMBINE ;
2013-04-05 06:13:26 +00:00
}
2013-06-01 13:13:04 +00:00
# endif
2013-06-01 13:10:30 +00:00
2014-09-08 11:01:22 +00:00
void FrameBuffer_ActivateBufferTexture ( s16 t , FrameBuffer * pBuffer )
2013-09-05 16:24:34 +00:00
{
2014-10-18 11:56:19 +00:00
if ( pBuffer = = NULL | | pBuffer - > m_pTexture = = NULL )
return ;
2015-02-09 12:27:39 +00:00
2015-05-06 12:36:07 +00:00
CachedTexture * pTexture = pBuffer - > m_pTexture ;
2015-02-09 12:27:39 +00:00
2015-03-11 11:02:09 +00:00
pTexture - > scaleS = pBuffer - > m_scaleX / ( float ) pTexture - > realWidth ;
pTexture - > scaleT = pBuffer - > m_scaleY / ( float ) pTexture - > realHeight ;
2013-09-05 16:24:34 +00:00
if ( gSP . textureTile [ t ] - > shifts > 10 )
2015-02-09 12:27:39 +00:00
pTexture - > shiftScaleS = ( float ) ( 1 < < ( 16 - gSP . textureTile [ t ] - > shifts ) ) ;
2013-09-05 16:24:34 +00:00
else if ( gSP . textureTile [ t ] - > shifts > 0 )
2015-02-09 12:27:39 +00:00
pTexture - > shiftScaleS = 1.0f / ( float ) ( 1 < < gSP . textureTile [ t ] - > shifts ) ;
2013-09-05 16:24:34 +00:00
else
2015-02-09 12:27:39 +00:00
pTexture - > shiftScaleS = 1.0f ;
2013-09-05 16:24:34 +00:00
if ( gSP . textureTile [ t ] - > shiftt > 10 )
2015-02-09 12:27:39 +00:00
pTexture - > shiftScaleT = ( float ) ( 1 < < ( 16 - gSP . textureTile [ t ] - > shiftt ) ) ;
2013-09-05 16:24:34 +00:00
else if ( gSP . textureTile [ t ] - > shiftt > 0 )
2015-02-09 12:27:39 +00:00
pTexture - > shiftScaleT = 1.0f / ( float ) ( 1 < < gSP . textureTile [ t ] - > shiftt ) ;
2013-09-05 16:24:34 +00:00
else
2015-02-09 12:27:39 +00:00
pTexture - > shiftScaleT = 1.0f ;
2013-09-05 16:24:34 +00:00
2014-09-08 11:01:22 +00:00
const u32 shift = gSP . textureTile [ t ] - > imageAddress - pBuffer - > m_startAddress ;
const u32 factor = pBuffer - > m_width < < pBuffer - > m_size > > 1 ;
2013-09-05 16:24:34 +00:00
if ( gSP . textureTile [ t ] - > loadType = = LOADTYPE_TILE )
{
2015-02-09 12:27:39 +00:00
pTexture - > offsetS = ( float ) pBuffer - > m_pLoadTile - > uls ;
pTexture - > offsetT = ( float ) ( pBuffer - > m_height - ( pBuffer - > m_pLoadTile - > ult + shift / factor ) ) ;
2013-09-05 16:24:34 +00:00
}
else
{
2015-02-09 12:27:39 +00:00
pTexture - > offsetS = ( float ) ( ( shift % factor ) > > pBuffer - > m_size < < 1 ) ;
pTexture - > offsetT = ( float ) ( pBuffer - > m_height - shift / factor ) ;
2013-09-05 16:24:34 +00:00
}
2014-10-03 16:27:05 +00:00
// frameBufferList().renderBuffer(pBuffer->m_startAddress);
2015-02-09 12:27:39 +00:00
textureCache ( ) . activateTexture ( t , pTexture ) ;
2014-04-27 12:26:12 +00:00
gDP . changed | = CHANGED_FB_TEXTURE ;
2013-09-05 16:24:34 +00:00
}
2014-09-08 11:01:22 +00:00
void FrameBuffer_ActivateBufferTextureBG ( s16 t , FrameBuffer * pBuffer )
2013-09-05 16:24:34 +00:00
{
2015-02-09 12:27:39 +00:00
if ( pBuffer = = NULL | | pBuffer - > m_pTexture = = NULL )
return ;
2013-09-05 16:24:34 +00:00
2015-05-06 12:36:07 +00:00
CachedTexture * pTexture = pBuffer - > m_pTexture ;
2015-02-09 12:27:39 +00:00
pTexture - > scaleS = video ( ) . getScaleX ( ) / ( float ) pTexture - > realWidth ;
pTexture - > scaleT = video ( ) . getScaleY ( ) / ( float ) pTexture - > realHeight ;
pTexture - > shiftScaleS = 1.0f ;
pTexture - > shiftScaleT = 1.0f ;
2013-09-05 16:24:34 +00:00
2015-02-09 12:27:39 +00:00
pTexture - > offsetS = gSP . bgImage . imageX ;
pTexture - > offsetT = ( float ) pBuffer - > m_height - gSP . bgImage . imageY ;
2013-09-05 16:24:34 +00:00
// FrameBuffer_RenderBuffer(buffer->startAddress);
2015-02-09 12:27:39 +00:00
textureCache ( ) . activateTexture ( t , pTexture ) ;
2014-04-27 12:26:12 +00:00
gDP . changed | = CHANGED_FB_TEXTURE ;
2013-09-05 16:24:34 +00:00
}
2013-08-10 11:12:17 +00:00
2014-04-10 14:44:07 +00:00
# ifndef GLES2
2013-09-05 16:24:34 +00:00
void FrameBufferToRDRAM : : Init ( )
2013-08-10 11:12:17 +00:00
{
2013-09-05 16:24:34 +00:00
// generate a framebuffer
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
glGenFramebuffers ( 1 , & m_FBO ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , m_FBO ) ;
2013-09-07 16:28:20 +00:00
2014-09-18 16:16:52 +00:00
m_pTexture = textureCache ( ) . addFrameBufferTexture ( ) ;
2013-09-07 16:28:20 +00:00
m_pTexture - > format = G_IM_FMT_RGBA ;
m_pTexture - > clampS = 1 ;
m_pTexture - > clampT = 1 ;
m_pTexture - > frameBufferTexture = TRUE ;
m_pTexture - > maskS = 0 ;
m_pTexture - > maskT = 0 ;
m_pTexture - > mirrorS = 0 ;
m_pTexture - > mirrorT = 0 ;
2015-02-24 05:13:11 +00:00
m_pTexture - > realWidth = 640 ;
2015-04-13 13:36:05 +00:00
m_pTexture - > realHeight = 580 ;
m_pTexture - > textureBytes = m_pTexture - > realWidth * m_pTexture - > realHeight * 4 ;
2014-09-18 16:16:52 +00:00
textureCache ( ) . addFrameBufferTextureSize ( m_pTexture - > textureBytes ) ;
2013-09-07 16:28:20 +00:00
glBindTexture ( GL_TEXTURE_2D , m_pTexture - > glName ) ;
2014-03-21 08:16:36 +00:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , m_pTexture - > realWidth , m_pTexture - > realHeight , 0 , GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
2013-09-05 16:24:34 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2013-09-07 16:28:20 +00:00
2014-04-08 15:18:20 +00:00
glFramebufferTexture2D ( GL_DRAW_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , m_pTexture - > glName , 0 ) ;
2013-09-05 16:24:34 +00:00
// check if everything is OK
assert ( checkFBO ( ) ) ;
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
2013-09-05 16:24:34 +00:00
// Generate and initialize Pixel Buffer Objects
2015-02-24 09:57:30 +00:00
glGenBuffers ( 1 , & m_PBO ) ;
glBindBuffer ( GL_PIXEL_PACK_BUFFER , m_PBO ) ;
2015-03-24 13:53:09 +00:00
glBufferData ( GL_PIXEL_PACK_BUFFER , m_pTexture - > textureBytes , NULL , GL_DYNAMIC_READ ) ;
2013-09-05 16:24:34 +00:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , 0 ) ;
}
void FrameBufferToRDRAM : : Destroy ( ) {
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
2015-02-24 09:57:30 +00:00
if ( m_FBO ! = 0 ) {
glDeleteFramebuffers ( 1 , & m_FBO ) ;
m_FBO = 0 ;
}
2014-09-11 07:38:56 +00:00
if ( m_pTexture ! = NULL ) {
textureCache ( ) . removeFrameBufferTexture ( m_pTexture ) ;
m_pTexture = NULL ;
}
2015-02-24 09:57:30 +00:00
if ( m_PBO ! = 0 ) {
glDeleteBuffers ( 1 , & m_PBO ) ;
m_PBO = 0 ;
}
2013-09-05 16:24:34 +00:00
}
2015-04-04 10:32:17 +00:00
void FrameBufferToRDRAM : : _copyWhite ( FrameBuffer * _pBuffer )
{
if ( _pBuffer - > m_size = = G_IM_SIZ_32b ) {
u32 * ptr_dst = ( u32 * ) ( RDRAM + _pBuffer - > m_startAddress ) ;
for ( u32 y = 0 ; y < VI . height ; + + y ) {
for ( u32 x = 0 ; x < VI . width ; + + x )
ptr_dst [ x + y * VI . width ] = 0xFFFFFFFF ;
}
}
else {
u16 * ptr_dst = ( u16 * ) ( RDRAM + _pBuffer - > m_startAddress ) ;
for ( u32 y = 0 ; y < VI . height ; + + y ) {
for ( u32 x = 0 ; x < VI . width ; + + x ) {
ptr_dst [ ( x + y * VI . width ) ^ 1 ] = 0xFFFF ;
}
}
}
2015-04-29 13:58:06 +00:00
_pBuffer - > m_copiedToRdram = true ;
_pBuffer - > copyRdram ( ) ;
2015-04-09 14:33:40 +00:00
2015-04-04 10:32:17 +00:00
_pBuffer - > m_cleared = false ;
}
void FrameBufferToRDRAM : : CopyToRDRAM ( u32 _address )
{
2015-05-05 11:07:21 +00:00
if ( VI . width = = 0 | | frameBufferList ( ) . getCurrent ( ) = = NULL ) // H width is zero or no current buffer. Don't copy
2014-09-27 06:17:01 +00:00
return ;
2015-02-24 09:57:30 +00:00
FrameBuffer * pBuffer = frameBufferList ( ) . findBuffer ( _address ) ;
2015-03-09 12:17:45 +00:00
if ( pBuffer = = NULL | | pBuffer - > m_width < VI . width | | pBuffer - > m_isOBScreen )
2013-09-04 02:15:05 +00:00
return ;
2013-08-10 11:12:17 +00:00
2015-04-04 10:32:17 +00:00
if ( ( config . generalEmulation . hacks & hack_subscreen ) ! = 0 ) {
_copyWhite ( pBuffer ) ;
return ;
}
2015-02-24 09:57:30 +00:00
_address = pBuffer - > m_startAddress ;
2015-02-13 12:29:15 +00:00
if ( config . video . multisampling ! = 0 ) {
pBuffer - > resolveMultisampledTexture ( ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , pBuffer - > m_resolveFBO ) ;
} else
glBindFramebuffer ( GL_READ_FRAMEBUFFER , pBuffer - > m_FBO ) ;
2013-09-04 02:15:05 +00:00
glReadBuffer ( GL_COLOR_ATTACHMENT0 ) ;
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , m_FBO ) ;
2015-03-17 12:03:45 +00:00
glScissor ( 0 , 0 , pBuffer - > m_pTexture - > realWidth , pBuffer - > m_pTexture - > realHeight ) ;
2014-03-21 09:38:39 +00:00
glBlitFramebuffer (
2014-09-21 12:15:22 +00:00
0 , 0 , video ( ) . getWidth ( ) , video ( ) . getHeight ( ) ,
2015-02-24 05:13:11 +00:00
0 , 0 , VI . width , VI . height ,
2015-04-09 13:59:39 +00:00
GL_COLOR_BUFFER_BIT , GL_NEAREST
2013-09-04 02:15:05 +00:00
) ;
2014-09-08 11:01:22 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , frameBufferList ( ) . getCurrent ( ) - > m_FBO ) ;
2013-09-04 02:15:05 +00:00
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , m_FBO ) ;
2014-03-21 08:16:36 +00:00
glReadBuffer ( GL_COLOR_ATTACHMENT0 ) ;
2014-10-13 12:37:43 +00:00
# ifndef GLES2
2015-03-24 14:10:19 +00:00
PBOBinder binder ( GL_PIXEL_PACK_BUFFER , m_PBO ) ;
glReadPixels ( 0 , 0 , VI . width , VI . height , GL_RGBA , GL_UNSIGNED_BYTE , 0 ) ;
2015-04-24 14:40:30 +00:00
isGLError ( ) ;
GLubyte * pixelData = ( GLubyte * ) glMapBufferRange ( GL_PIXEL_PACK_BUFFER , 0 , VI . width * VI . height * 4 , GL_MAP_READ_BIT ) ;
isGLError ( ) ;
2015-03-24 14:10:19 +00:00
if ( pixelData = = NULL )
2013-09-05 16:24:34 +00:00
return ;
2014-03-21 08:16:36 +00:00
# else
m_curIndex = 0 ;
const u32 nextIndex = 0 ;
GLubyte * pixelData = ( GLubyte * ) malloc ( VI . width * VI . height * 4 ) ;
if ( pixelData = = NULL )
return ;
glReadPixels ( 0 , 0 , VI . width , VI . height , GL_RGBA , GL_UNSIGNED_BYTE , pixelData ) ;
# endif // GLES2
2013-09-05 16:24:34 +00:00
2015-04-09 16:40:07 +00:00
const u32 stride = pBuffer - > m_width < < pBuffer - > m_size > > 1 ;
const u32 height = _cutHeight ( _address , VI . height , stride ) ;
2014-09-08 11:01:22 +00:00
if ( pBuffer - > m_size = = G_IM_SIZ_32b ) {
2015-02-24 09:57:30 +00:00
u32 * ptr_dst = ( u32 * ) ( RDRAM + _address ) ;
2013-09-04 02:15:05 +00:00
u32 * ptr_src = ( u32 * ) pixelData ;
2015-04-09 16:40:07 +00:00
for ( u32 y = 0 ; y < height ; + + y ) {
2013-09-04 02:15:05 +00:00
for ( u32 x = 0 ; x < VI . width ; + + x )
2015-04-09 16:40:07 +00:00
ptr_dst [ x + y * VI . width ] = ptr_src [ x + ( height - y - 1 ) * VI . width ] ;
2013-09-04 02:15:05 +00:00
}
} else {
2015-02-24 09:57:30 +00:00
u16 * ptr_dst = ( u16 * ) ( RDRAM + _address ) ;
2013-09-04 02:15:05 +00:00
RGBA * ptr_src = ( RGBA * ) pixelData ;
2015-04-09 16:40:07 +00:00
for ( u32 y = 0 ; y < height ; + + y ) {
2013-09-04 02:15:05 +00:00
for ( u32 x = 0 ; x < VI . width ; + + x ) {
2015-04-09 16:40:07 +00:00
const RGBA & c = ptr_src [ x + ( height - y - 1 ) * VI . width ] ;
ptr_dst [ ( x + y * VI . width ) ^ 1 ] = ( ( c . r > > 3 ) < < 11 ) | ( ( c . g > > 3 ) < < 6 ) | ( ( c . b > > 3 ) < < 1 ) | ( c . a = = 0 ? 0 : 1 ) ;
2013-08-10 11:12:17 +00:00
}
}
}
2015-04-29 13:58:06 +00:00
pBuffer - > m_copiedToRdram = true ;
pBuffer - > copyRdram ( ) ;
2015-03-09 09:28:43 +00:00
pBuffer - > m_cleared = false ;
2015-02-24 09:57:30 +00:00
# ifndef GLES2
2013-09-05 16:24:34 +00:00
glUnmapBuffer ( GL_PIXEL_PACK_BUFFER ) ;
2014-03-21 08:16:36 +00:00
# else
free ( pixelData ) ;
# endif
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
2015-04-03 14:58:45 +00:00
gDP . changed | = CHANGED_SCISSOR ;
2013-08-10 11:12:17 +00:00
}
2014-04-10 14:44:07 +00:00
# endif // GLES2
2013-08-10 11:12:17 +00:00
2015-02-24 09:57:30 +00:00
void FrameBuffer_CopyToRDRAM ( u32 _address )
2013-06-09 11:55:21 +00:00
{
2014-04-10 14:44:07 +00:00
# ifndef GLES2
2015-02-24 09:57:30 +00:00
g_fbToRDRAM . CopyToRDRAM ( _address ) ;
2014-04-10 14:44:07 +00:00
# endif
2013-06-09 11:55:21 +00:00
}
2013-09-07 16:31:04 +00:00
2014-03-21 08:16:36 +00:00
# ifndef GLES2
2013-11-12 08:41:19 +00:00
void DepthBufferToRDRAM : : Init ( )
{
// generate a framebuffer
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
glGenFramebuffers ( 1 , & m_FBO ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , m_FBO ) ;
2013-11-12 08:41:19 +00:00
2015-02-02 08:56:53 +00:00
m_pColorTexture = textureCache ( ) . addFrameBufferTexture ( ) ;
m_pColorTexture - > format = G_IM_FMT_I ;
m_pColorTexture - > clampS = 1 ;
m_pColorTexture - > clampT = 1 ;
m_pColorTexture - > frameBufferTexture = TRUE ;
m_pColorTexture - > maskS = 0 ;
m_pColorTexture - > maskT = 0 ;
m_pColorTexture - > mirrorS = 0 ;
m_pColorTexture - > mirrorT = 0 ;
m_pColorTexture - > realWidth = 640 ;
2015-04-13 13:36:05 +00:00
m_pColorTexture - > realHeight = 580 ;
2015-02-02 08:56:53 +00:00
m_pColorTexture - > textureBytes = m_pColorTexture - > realWidth * m_pColorTexture - > realHeight ;
textureCache ( ) . addFrameBufferTextureSize ( m_pColorTexture - > textureBytes ) ;
m_pDepthTexture = textureCache ( ) . addFrameBufferTexture ( ) ;
m_pDepthTexture - > format = G_IM_FMT_I ;
m_pDepthTexture - > clampS = 1 ;
m_pDepthTexture - > clampT = 1 ;
m_pDepthTexture - > frameBufferTexture = TRUE ;
m_pDepthTexture - > maskS = 0 ;
m_pDepthTexture - > maskT = 0 ;
m_pDepthTexture - > mirrorS = 0 ;
m_pDepthTexture - > mirrorT = 0 ;
m_pDepthTexture - > realWidth = 640 ;
2015-04-13 13:36:05 +00:00
m_pDepthTexture - > realHeight = 580 ;
2015-02-02 08:56:53 +00:00
m_pDepthTexture - > textureBytes = m_pDepthTexture - > realWidth * m_pDepthTexture - > realHeight * sizeof ( float ) ;
textureCache ( ) . addFrameBufferTextureSize ( m_pDepthTexture - > textureBytes ) ;
glBindTexture ( GL_TEXTURE_2D , m_pColorTexture - > glName ) ;
2015-05-04 09:52:45 +00:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_R8 , m_pColorTexture - > realWidth , m_pColorTexture - > realHeight , 0 , GL_RED , GL_UNSIGNED_BYTE , NULL ) ;
2015-02-02 08:56:53 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
2015-01-28 13:58:55 +00:00
2015-02-02 08:56:53 +00:00
glBindTexture ( GL_TEXTURE_2D , m_pDepthTexture - > glName ) ;
2015-05-04 09:40:17 +00:00
glTexImage2D ( GL_TEXTURE_2D , 0 , DEPTH_COMPONENT_FORMAT , m_pDepthTexture - > realWidth , m_pDepthTexture - > realHeight , 0 , GL_DEPTH_COMPONENT , GL_FLOAT , NULL ) ;
2015-01-28 13:58:55 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
2015-02-02 08:56:53 +00:00
2013-11-12 08:41:19 +00:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2015-02-02 08:56:53 +00:00
glFramebufferTexture2D ( GL_DRAW_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , m_pColorTexture - > glName , 0 ) ;
glFramebufferTexture2D ( GL_DRAW_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , m_pDepthTexture - > glName , 0 ) ;
2013-11-12 08:41:19 +00:00
// check if everything is OK
assert ( checkFBO ( ) ) ;
2015-01-28 13:58:55 +00:00
assert ( ! isGLError ( ) ) ;
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
2013-11-12 08:41:19 +00:00
// Generate and initialize Pixel Buffer Objects
2014-10-18 17:25:20 +00:00
glGenBuffers ( 1 , & m_PBO ) ;
glBindBuffer ( GL_PIXEL_PACK_BUFFER , m_PBO ) ;
2015-04-13 13:36:05 +00:00
glBufferData ( GL_PIXEL_PACK_BUFFER , m_pDepthTexture - > realWidth * m_pDepthTexture - > realHeight * sizeof ( float ) , NULL , GL_DYNAMIC_READ ) ;
2013-11-12 08:41:19 +00:00
glBindBuffer ( GL_PIXEL_PACK_BUFFER , 0 ) ;
}
void DepthBufferToRDRAM : : Destroy ( ) {
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
glDeleteFramebuffers ( 1 , & m_FBO ) ;
2013-11-18 03:30:20 +00:00
m_FBO = 0 ;
2015-02-02 08:56:53 +00:00
if ( m_pColorTexture ! = NULL ) {
textureCache ( ) . removeFrameBufferTexture ( m_pColorTexture ) ;
m_pColorTexture = NULL ;
}
if ( m_pDepthTexture ! = NULL ) {
textureCache ( ) . removeFrameBufferTexture ( m_pDepthTexture ) ;
m_pDepthTexture = NULL ;
2014-09-11 07:38:56 +00:00
}
2014-10-18 17:25:20 +00:00
glDeleteBuffers ( 1 , & m_PBO ) ;
m_PBO = 0 ;
2013-11-12 08:41:19 +00:00
}
2014-10-18 17:25:20 +00:00
bool DepthBufferToRDRAM : : CopyToRDRAM ( u32 _address ) {
2014-10-03 09:51:12 +00:00
if ( VI . width = = 0 ) // H width is zero. Don't copy
2014-10-18 15:38:32 +00:00
return false ;
if ( m_lastDList = = RSP . DList ) // Already read;
2015-04-01 13:06:14 +00:00
return true ;
2014-10-18 17:25:20 +00:00
FrameBuffer * pBuffer = frameBufferList ( ) . findBuffer ( _address ) ;
2015-03-16 13:52:43 +00:00
if ( pBuffer = = NULL | | pBuffer - > m_width < VI . width | | pBuffer - > m_pDepthBuffer = = NULL | | ! pBuffer - > m_pDepthBuffer - > m_cleared )
2014-10-18 15:38:32 +00:00
return false ;
2013-11-12 08:41:19 +00:00
2014-10-18 15:38:32 +00:00
m_lastDList = RSP . DList ;
2014-09-08 11:01:22 +00:00
DepthBuffer * pDepthBuffer = pBuffer - > m_pDepthBuffer ;
2014-10-18 17:25:20 +00:00
const u32 address = pDepthBuffer - > m_address ;
2015-04-01 06:33:28 +00:00
if ( address + VI . width * VI . height * 2 > RDRAMSize )
return false ;
2015-02-26 12:00:40 +00:00
if ( config . video . multisampling = = 0 )
glBindFramebuffer ( GL_READ_FRAMEBUFFER , pBuffer - > m_FBO ) ;
else {
pDepthBuffer - > resolveDepthBufferTexture ( pBuffer ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , pBuffer - > m_resolveFBO ) ;
}
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , m_FBO ) ;
2015-03-17 12:03:45 +00:00
glScissor ( 0 , 0 , pBuffer - > m_pTexture - > realWidth , pBuffer - > m_pTexture - > realHeight ) ;
2014-03-21 09:38:39 +00:00
glBlitFramebuffer (
2014-09-21 12:15:22 +00:00
0 , 0 , video ( ) . getWidth ( ) , video ( ) . getHeight ( ) ,
2014-09-08 11:01:22 +00:00
0 , 0 , pBuffer - > m_width , pBuffer - > m_height ,
2015-01-28 13:58:55 +00:00
GL_DEPTH_BUFFER_BIT , GL_NEAREST
2013-11-12 08:41:19 +00:00
) ;
2014-09-08 11:01:22 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , frameBufferList ( ) . getCurrent ( ) - > m_FBO ) ;
2013-11-12 08:41:19 +00:00
2015-03-24 14:10:19 +00:00
PBOBinder binder ( GL_PIXEL_PACK_BUFFER , m_PBO ) ;
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , m_FBO ) ;
2015-01-28 13:58:55 +00:00
glReadPixels ( 0 , 0 , VI . width , VI . height , GL_DEPTH_COMPONENT , GL_FLOAT , 0 ) ;
2013-11-12 08:41:19 +00:00
2015-04-24 14:40:30 +00:00
GLubyte * pixelData = ( GLubyte * ) glMapBufferRange ( GL_PIXEL_PACK_BUFFER , 0 , VI . width * VI . height * 4 , GL_MAP_READ_BIT ) ;
2015-03-24 14:10:19 +00:00
if ( pixelData = = NULL )
2014-10-18 15:38:32 +00:00
return false ;
2013-11-12 08:41:19 +00:00
2015-01-28 13:58:55 +00:00
f32 * ptr_src = ( f32 * ) pixelData ;
2014-10-18 17:25:20 +00:00
u16 * ptr_dst = ( u16 * ) ( RDRAM + address ) ;
2015-01-27 11:56:22 +00:00
const u16 * const zLUT = depthBufferList ( ) . getZLUT ( ) ;
2015-04-29 16:14:57 +00:00
const u32 height = _cutHeight ( address , min ( VI . height , pDepthBuffer - > m_lry ) , pBuffer - > m_width * 2 ) ;
2013-11-12 08:41:19 +00:00
2015-04-29 16:14:57 +00:00
for ( u32 y = pDepthBuffer - > m_uly ; y < height ; + + y ) {
2013-11-12 08:41:19 +00:00
for ( u32 x = 0 ; x < VI . width ; + + x ) {
2015-04-09 16:40:07 +00:00
f32 z = ptr_src [ x + ( height - y - 1 ) * VI . width ] ;
2015-03-05 13:44:38 +00:00
u32 idx = 0x3FFFF ;
if ( z < 1.0f ) {
z * = 262144.0f ;
idx = min ( 0x3FFFFU , u32 ( floorf ( z + 0.5f ) ) ) ;
2015-01-28 13:58:55 +00:00
}
2015-03-05 13:44:38 +00:00
ptr_dst [ ( x + y * VI . width ) ^ 1 ] = zLUT [ idx ] ;
2013-11-12 08:41:19 +00:00
}
}
2015-03-09 09:28:43 +00:00
pDepthBuffer - > m_cleared = false ;
pBuffer = frameBufferList ( ) . findBuffer ( pDepthBuffer - > m_address ) ;
2015-03-09 14:24:23 +00:00
if ( pBuffer ! = NULL )
2015-03-09 09:28:43 +00:00
pBuffer - > m_cleared = false ;
2013-11-12 08:41:19 +00:00
glUnmapBuffer ( GL_PIXEL_PACK_BUFFER ) ;
2014-03-21 09:38:39 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , 0 ) ;
2015-04-01 13:06:14 +00:00
gDP . changed | = CHANGED_SCISSOR ;
2014-10-18 15:38:32 +00:00
return true ;
2013-11-12 08:41:19 +00:00
}
2014-03-21 08:16:36 +00:00
# endif // GLES2
2013-11-12 08:41:19 +00:00
2014-10-18 15:38:32 +00:00
bool FrameBuffer_CopyDepthBuffer ( u32 address ) {
2014-03-21 08:16:36 +00:00
# ifndef GLES2
2014-10-18 15:38:32 +00:00
return g_dbToRDRAM . CopyToRDRAM ( address ) ;
2015-04-23 11:25:21 +00:00
# else
return false ;
2014-03-21 08:16:36 +00:00
# endif
2013-11-12 08:41:19 +00:00
}
2013-09-07 16:31:04 +00:00
void RDRAMtoFrameBuffer : : Init ( )
{
2014-09-18 16:16:52 +00:00
m_pTexture = textureCache ( ) . addFrameBufferTexture ( ) ;
2013-09-07 16:31:04 +00:00
m_pTexture - > format = G_IM_FMT_RGBA ;
m_pTexture - > clampS = 1 ;
m_pTexture - > clampT = 1 ;
m_pTexture - > frameBufferTexture = TRUE ;
m_pTexture - > maskS = 0 ;
m_pTexture - > maskT = 0 ;
m_pTexture - > mirrorS = 0 ;
m_pTexture - > mirrorT = 0 ;
2015-03-24 13:55:53 +00:00
m_pTexture - > realWidth = 640 ;
2015-04-13 13:36:05 +00:00
m_pTexture - > realHeight = 580 ;
2013-09-07 16:31:04 +00:00
m_pTexture - > textureBytes = m_pTexture - > realWidth * m_pTexture - > realHeight * 4 ;
2014-09-18 16:16:52 +00:00
textureCache ( ) . addFrameBufferTextureSize ( m_pTexture - > textureBytes ) ;
2013-09-07 16:31:04 +00:00
glBindTexture ( GL_TEXTURE_2D , m_pTexture - > glName ) ;
2014-03-21 08:16:36 +00:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , m_pTexture - > realWidth , m_pTexture - > realHeight , 0 , GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
2013-09-07 16:31:04 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
// Generate Pixel Buffer Object. Initialize it later
2014-03-21 08:16:36 +00:00
# ifndef GLES2
2013-09-07 16:31:04 +00:00
glGenBuffers ( 1 , & m_PBO ) ;
2014-03-21 08:16:36 +00:00
# endif
2013-09-07 16:31:04 +00:00
}
void RDRAMtoFrameBuffer : : Destroy ( )
{
2014-09-11 07:38:56 +00:00
if ( m_pTexture ! = NULL ) {
textureCache ( ) . removeFrameBufferTexture ( m_pTexture ) ;
m_pTexture = NULL ;
}
2014-03-21 08:16:36 +00:00
# ifndef GLES2
2013-09-07 16:31:04 +00:00
glDeleteBuffers ( 1 , & m_PBO ) ;
2013-11-18 03:30:20 +00:00
m_PBO = 0 ;
2014-03-21 08:16:36 +00:00
# endif
2013-09-07 16:31:04 +00:00
}
2013-09-15 14:40:16 +00:00
void RDRAMtoFrameBuffer : : CopyFromRDRAM ( u32 _address , bool _bUseAlpha )
2013-09-07 16:31:04 +00:00
{
2014-09-08 11:01:22 +00:00
FrameBuffer * pBuffer = frameBufferList ( ) . findBuffer ( _address ) ;
if ( pBuffer = = NULL | | pBuffer - > m_size < G_IM_SIZ_16b )
2013-09-07 16:31:04 +00:00
return ;
2015-02-21 05:52:01 +00:00
if ( pBuffer - > m_startAddress = = _address & & gDP . colorImage . changed ! = 0 )
return ;
2013-09-07 16:31:04 +00:00
2015-03-30 12:06:21 +00:00
const bool bUseAlpha = _bUseAlpha & & pBuffer - > m_changed ;
2015-02-21 05:52:01 +00:00
const u32 address = pBuffer - > m_startAddress ;
2014-09-08 11:01:22 +00:00
const u32 width = pBuffer - > m_width ;
2015-02-21 05:52:01 +00:00
const u32 height = pBuffer - > m_startAddress = = _address ? VI . real_height : pBuffer - > m_height ;
2013-09-07 16:31:04 +00:00
m_pTexture - > width = width ;
m_pTexture - > height = height ;
const u32 dataSize = width * height * 4 ;
2014-03-21 08:16:36 +00:00
# ifndef GLES2
2015-03-24 14:04:39 +00:00
PBOBinder binder ( GL_PIXEL_UNPACK_BUFFER , m_PBO ) ;
2013-09-07 16:31:04 +00:00
glBufferData ( GL_PIXEL_UNPACK_BUFFER , dataSize , NULL , GL_DYNAMIC_DRAW ) ;
2015-04-24 14:40:30 +00:00
GLubyte * ptr = ( GLubyte * ) glMapBufferRange ( GL_PIXEL_UNPACK_BUFFER , 0 , dataSize , GL_MAP_WRITE_BIT ) ;
2014-03-21 08:16:36 +00:00
# else
m_PBO = ( GLubyte * ) malloc ( dataSize ) ;
GLubyte * ptr = m_PBO ;
PBOBinder binder ( m_PBO ) ;
# endif // GLES2
2013-09-07 16:31:04 +00:00
if ( ptr = = NULL )
return ;
2015-02-21 05:52:01 +00:00
u8 * image = RDRAM + address ;
2013-09-07 16:31:04 +00:00
u32 * dst = ( u32 * ) ptr ;
u32 empty = 0 ;
2015-03-30 12:07:25 +00:00
u32 r , g , b , a , idx ;
2014-09-08 11:01:22 +00:00
if ( pBuffer - > m_size = = G_IM_SIZ_16b ) {
2013-09-07 16:31:04 +00:00
u16 * src = ( u16 * ) image ;
u16 col ;
2015-02-21 05:52:01 +00:00
const u32 bound = ( RDRAMSize + 1 - address ) > > 1 ;
2013-09-07 16:31:04 +00:00
for ( u32 y = 0 ; y < height ; y + + )
{
for ( u32 x = 0 ; x < width ; x + + )
{
idx = ( x + ( height - y - 1 ) * width ) ^ 1 ;
if ( idx > = bound )
break ;
col = src [ idx ] ;
2015-03-30 12:06:21 +00:00
if ( bUseAlpha )
2015-02-21 05:52:01 +00:00
src [ idx ] = 0 ;
2013-09-07 16:31:04 +00:00
empty | = col ;
r = ( ( col > > 11 ) & 31 ) < < 3 ;
g = ( ( col > > 6 ) & 31 ) < < 3 ;
b = ( ( col > > 1 ) & 31 ) < < 3 ;
2015-03-30 12:07:25 +00:00
a = ( col & 1 ) > 0 & & ( r | g | b ) > 0 ? 0xff : 0U ;
2015-02-27 13:51:53 +00:00
dst [ x + y * width ] = ( a < < 24 ) | ( b < < 16 ) | ( g < < 8 ) | r ;
2013-09-07 16:31:04 +00:00
}
}
} else {
// 32 bit
u32 * src = ( u32 * ) image ;
u32 col ;
2015-02-21 05:52:01 +00:00
const u32 bound = ( RDRAMSize + 1 - address ) > > 2 ;
2013-09-07 16:31:04 +00:00
for ( u32 y = 0 ; y < height ; y + + )
{
for ( u32 x = 0 ; x < width ; x + + )
{
idx = x + ( height - y - 1 ) * width ;
if ( idx > = bound )
break ;
col = src [ idx ] ;
2015-03-30 12:06:21 +00:00
if ( bUseAlpha )
2015-02-21 05:52:01 +00:00
src [ idx ] = 0 ;
2013-09-07 16:31:04 +00:00
empty | = col ;
r = ( col > > 24 ) & 0xff ;
g = ( col > > 16 ) & 0xff ;
b = ( col > > 8 ) & 0xff ;
2015-03-30 12:07:25 +00:00
a = ( r | g | b ) > 0 ? col & 0xff : 0U ;
2013-09-07 16:31:04 +00:00
dst [ x + y * width ] = ( a < < 24 ) | ( b < < 16 ) | ( g < < 8 ) | r ;
}
}
}
2014-03-21 08:16:36 +00:00
# ifndef GLES2
2013-09-07 16:31:04 +00:00
glUnmapBuffer ( GL_PIXEL_UNPACK_BUFFER ) ; // release the mapped buffer
2014-03-21 08:16:36 +00:00
# endif
2013-09-07 16:31:04 +00:00
if ( empty = = 0 )
return ;
glBindTexture ( GL_TEXTURE_2D , m_pTexture - > glName ) ;
2014-03-21 08:16:36 +00:00
# ifndef GLES2
2013-09-07 16:31:04 +00:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_BYTE , 0 ) ;
2014-03-21 08:16:36 +00:00
# else
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , width , height , GL_RGBA , GL_UNSIGNED_BYTE , m_PBO ) ;
# endif
2014-09-21 12:15:22 +00:00
2014-04-08 16:48:04 +00:00
m_pTexture - > scaleS = 1.0f / ( float ) m_pTexture - > realWidth ;
m_pTexture - > scaleT = 1.0f / ( float ) m_pTexture - > realHeight ;
m_pTexture - > shiftScaleS = 1.0f ;
m_pTexture - > shiftScaleT = 1.0f ;
m_pTexture - > offsetS = 0 ;
m_pTexture - > offsetT = ( float ) m_pTexture - > height ;
2014-09-18 16:16:52 +00:00
textureCache ( ) . activateTexture ( 0 , m_pTexture ) ;
2013-09-07 16:31:04 +00:00
2015-02-27 05:41:52 +00:00
gDPTile tile0 ;
tile0 . fuls = tile0 . fult = 0.0f ;
gDPTile * pTile0 = gSP . textureTile [ 0 ] ;
gSP . textureTile [ 0 ] = & tile0 ;
2015-03-15 05:28:53 +00:00
if ( _bUseAlpha ) {
CombinerInfo : : get ( ) . setCombine ( EncodeCombineMode ( 0 , 0 , 0 , TEXEL0 , 0 , 0 , 0 , TEXEL0 , 0 , 0 , 0 , TEXEL0 , 0 , 0 , 0 , TEXEL0 ) ) ;
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
}
else {
CombinerInfo : : get ( ) . setCombine ( EncodeCombineMode ( 0 , 0 , 0 , TEXEL0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , TEXEL0 , 0 , 0 , 0 , 1 ) ) ;
glDisable ( GL_BLEND ) ;
}
glDisable ( GL_DEPTH_TEST ) ;
const u32 gspChanged = gSP . changed & CHANGED_CPU_FB_WRITE ;
gSP . changed = gDP . changed = 0 ;
2015-03-01 12:13:07 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , pBuffer - > m_FBO ) ;
2014-10-21 15:06:19 +00:00
OGLRender : : TexturedRectParams params ( 0.0f , 0.0f , ( float ) width , ( float ) height , 0.0f , 0.0f , width - 1.0f , height - 1.0f , false ) ;
2015-02-21 05:52:01 +00:00
video ( ) . getRender ( ) . drawTexturedRect ( params ) ;
2015-03-01 12:13:07 +00:00
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , frameBufferList ( ) . getCurrent ( ) - > m_FBO ) ;
2015-02-21 05:52:01 +00:00
2015-02-27 05:41:52 +00:00
gSP . textureTile [ 0 ] = pTile0 ;
2015-04-03 14:52:13 +00:00
gSP . changed | = gspChanged | CHANGED_TEXTURE ;
gDP . changed | = CHANGED_RENDERMODE | CHANGED_COMBINE ;
2013-09-07 16:31:04 +00:00
}
2013-09-15 14:40:16 +00:00
void FrameBuffer_CopyFromRDRAM ( u32 address , bool bUseAlpha )
2013-09-07 16:31:04 +00:00
{
2013-09-15 14:40:16 +00:00
g_RDRAMtoFB . CopyFromRDRAM ( address , bUseAlpha ) ;
2013-09-07 16:31:04 +00:00
}