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"
|
2015-11-23 12:36:03 +00:00
|
|
|
#include "FrameBufferInfo.h"
|
2013-06-01 13:10:30 +00:00
|
|
|
|
2014-09-20 17:34:07 +00:00
|
|
|
using namespace std;
|
|
|
|
|
2014-04-10 14:44:07 +00:00
|
|
|
#ifndef GLES2
|
2013-09-05 16:24:34 +00:00
|
|
|
class FrameBufferToRDRAM
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FrameBufferToRDRAM() :
|
2015-11-23 13:03:33 +00:00
|
|
|
m_FBO(0),
|
|
|
|
m_pTexture(nullptr),
|
|
|
|
m_pCurFrameBuffer(nullptr),
|
|
|
|
m_curIndex(-1),
|
2015-11-29 18:30:50 +00:00
|
|
|
m_frameCount(-1)
|
2015-10-03 17:23:18 +00:00
|
|
|
{
|
2015-10-31 03:11:33 +00:00
|
|
|
m_PBO[0] = m_PBO[1] = m_PBO[2] = 0;
|
2015-10-03 17:23:18 +00:00
|
|
|
}
|
2013-09-05 16:24:34 +00:00
|
|
|
|
|
|
|
void Init();
|
|
|
|
void Destroy();
|
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
void copyToRDRAM(u32 _address, bool _sync);
|
|
|
|
void copyChunkToRDRAM(u32 _address);
|
2013-09-05 16:24:34 +00:00
|
|
|
|
|
|
|
private:
|
2015-06-16 13:43:15 +00:00
|
|
|
union RGBA {
|
|
|
|
struct {
|
|
|
|
u8 r, g, b, a;
|
|
|
|
};
|
|
|
|
u32 raw;
|
2013-09-05 16:24:34 +00:00
|
|
|
};
|
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
bool _prepareCopy(u32 _address);
|
|
|
|
void _copy(u32 _startAddress, u32 _endAddress, bool _sync);
|
|
|
|
|
|
|
|
// Convert pixel from video memory to N64 buffer format.
|
|
|
|
static u8 _RGBAtoR8(u8 _c);
|
|
|
|
static u16 _RGBAtoRGBA16(u32 _c);
|
|
|
|
static u32 _RGBAtoRGBA32(u32 _c);
|
|
|
|
|
2013-09-07 16:28:20 +00:00
|
|
|
GLuint m_FBO;
|
|
|
|
CachedTexture * m_pTexture;
|
2015-11-23 13:03:33 +00:00
|
|
|
FrameBuffer * m_pCurFrameBuffer;
|
2015-10-03 17:23:18 +00:00
|
|
|
u32 m_curIndex;
|
2015-11-23 13:03:33 +00:00
|
|
|
u32 m_frameCount;
|
2015-10-31 03:11:33 +00:00
|
|
|
GLuint m_PBO[3];
|
2013-09-05 16:24:34 +00:00
|
|
|
};
|
|
|
|
|
2013-11-12 08:41:19 +00:00
|
|
|
class DepthBufferToRDRAM
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DepthBufferToRDRAM() :
|
2015-11-23 13:03:33 +00:00
|
|
|
m_FBO(0),
|
|
|
|
m_PBO(0),
|
|
|
|
m_frameCount(-1),
|
|
|
|
m_pColorTexture(nullptr),
|
|
|
|
m_pDepthTexture(nullptr),
|
|
|
|
m_pCurDepthBuffer(nullptr)
|
2014-10-18 17:25:20 +00:00
|
|
|
{}
|
2013-11-12 08:41:19 +00:00
|
|
|
|
|
|
|
void Init();
|
|
|
|
void Destroy();
|
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
bool copyToRDRAM(u32 _address);
|
|
|
|
bool copyChunkToRDRAM(u32 _address);
|
2013-11-12 08:41:19 +00:00
|
|
|
|
|
|
|
private:
|
2015-11-23 13:03:33 +00:00
|
|
|
bool _prepareCopy(u32 _address);
|
|
|
|
bool _copy(u32 _startAddress, u32 _endAddress);
|
|
|
|
|
|
|
|
// Convert pixel from video memory to N64 depth buffer format.
|
|
|
|
static u16 _FloatToUInt16(f32 _z);
|
|
|
|
|
2013-11-12 08:41:19 +00:00
|
|
|
GLuint m_FBO;
|
2014-10-18 17:25:20 +00:00
|
|
|
GLuint m_PBO;
|
2015-11-23 13:03:33 +00:00
|
|
|
u32 m_frameCount;
|
2015-02-02 08:56:53 +00:00
|
|
|
CachedTexture * m_pColorTexture;
|
|
|
|
CachedTexture * m_pDepthTexture;
|
2015-11-23 13:03:33 +00:00
|
|
|
DepthBuffer * m_pCurDepthBuffer;
|
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-10-10 16:36:25 +00:00
|
|
|
FrameBuffer::FrameBuffer() :
|
|
|
|
m_startAddress(0), m_endAddress(0), m_size(0), m_width(0), m_height(0), m_fillcolor(0), m_validityChecked(0),
|
|
|
|
m_scaleX(0), m_scaleY(0),
|
|
|
|
m_copiedToRdram(false), m_fingerprint(false), m_cleared(false), m_changed(false), m_cfb(false),
|
|
|
|
m_isDepthBuffer(false), m_isPauseScreen(false), m_isOBScreen(false), m_needHeightCorrection(false),
|
2015-12-23 10:21:55 +00:00
|
|
|
m_postProcessed(0), m_pLoadTile(NULL),
|
2015-10-10 16:34:23 +00:00
|
|
|
m_pDepthBuffer(NULL), m_pResolveTexture(NULL), m_resolveFBO(0), 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-10-10 16:34:23 +00:00
|
|
|
m_validityChecked(_other.m_validityChecked), m_scaleX(_other.m_scaleX), m_scaleY(_other.m_scaleY), m_copiedToRdram(_other.m_copiedToRdram), m_fingerprint(_other.m_fingerprint), m_cleared(_other.m_cleared), m_changed(_other.m_changed),
|
2015-10-10 16:36:25 +00:00
|
|
|
m_cfb(_other.m_cfb), m_isDepthBuffer(_other.m_isDepthBuffer), m_isPauseScreen(_other.m_isPauseScreen), m_isOBScreen(_other.m_isOBScreen), m_needHeightCorrection(_other.m_needHeightCorrection), m_postProcessed(_other.m_postProcessed),
|
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;
|
2015-05-06 13:47:12 +00:00
|
|
|
_pTexture->frameBufferTexture = CachedTexture::fbOneSample;
|
2015-02-09 12:27:39 +00:00
|
|
|
_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)
|
2015-06-02 12:57:24 +00:00
|
|
|
_pTexture->textureBytes *= fboFormats.colorFormatBytes;
|
|
|
|
else
|
|
|
|
_pTexture->textureBytes *= fboFormats.monochromeFormatBytes;
|
2015-02-09 12:27:39 +00:00
|
|
|
textureCache().addFrameBufferTextureSize(_pTexture->textureBytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBuffer::_setAndAttachTexture(u16 _size, CachedTexture *_pTexture)
|
|
|
|
{
|
|
|
|
glBindTexture(GL_TEXTURE_2D, _pTexture->glName);
|
2015-05-16 08:56:42 +00:00
|
|
|
if (_size > G_IM_SIZ_8b)
|
2015-06-02 12:57:24 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, fboFormats.colorInternalFormat, _pTexture->realWidth, _pTexture->realHeight, 0, fboFormats.colorFormat, fboFormats.colorType, NULL);
|
2015-05-16 08:56:42 +00:00
|
|
|
else
|
2015-06-02 12:57:24 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, fboFormats.monochromeInternalFormat, _pTexture->realWidth, _pTexture->realHeight, 0, fboFormats.monochromeFormat, fboFormats.monochromeType, NULL);
|
2015-02-09 12:27:39 +00:00
|
|
|
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;
|
2015-10-31 02:27:34 +00:00
|
|
|
if (m_width != VI.width && config.frameBufferEmulation.copyAuxToRDRAM != 0) {
|
|
|
|
m_scaleX = 1.0f;
|
|
|
|
m_scaleY = 1.0f;
|
|
|
|
} else {
|
|
|
|
m_scaleX = ogl.getScaleX();
|
|
|
|
m_scaleY = ogl.getScaleY();
|
|
|
|
}
|
2015-02-09 12:27:39 +00:00
|
|
|
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-08-02 19:01:02 +00:00
|
|
|
m_fingerprint = 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
|
2015-06-02 12:57:24 +00:00
|
|
|
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, config.video.multisampling, fboFormats.monochromeInternalFormat, 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
|
2015-06-02 12:57:24 +00:00
|
|
|
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, config.video.multisampling, fboFormats.monochromeInternalFormat, m_pTexture->realWidth, m_pTexture->realHeight, false);
|
2015-04-23 08:51:35 +00:00
|
|
|
#endif
|
2015-05-06 13:47:12 +00:00
|
|
|
m_pTexture->frameBufferTexture = CachedTexture::fbMultiSample;
|
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;
|
2015-09-25 06:21:20 +00:00
|
|
|
const u32 endAddress = m_startAddress + ((m_width * _height) << m_size >> 1) - 1;
|
2015-03-11 10:59:42 +00:00
|
|
|
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)
|
|
|
|
{
|
2015-11-15 09:26:03 +00:00
|
|
|
if (_address > RDRAMSize)
|
|
|
|
return 0;
|
2015-04-29 13:58:06 +00:00
|
|
|
if (_address + _stride * _height > RDRAMSize)
|
2015-11-15 09:26:03 +00:00
|
|
|
return (RDRAMSize - _address) / _stride;
|
2015-04-29 13:58:06 +00:00
|
|
|
return _height;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBuffer::copyRdram()
|
|
|
|
{
|
|
|
|
const u32 stride = m_width << m_size >> 1;
|
|
|
|
const u32 height = _cutHeight(m_startAddress, m_height, stride);
|
2015-11-15 09:26:03 +00:00
|
|
|
if (height == 0)
|
|
|
|
return;
|
2015-04-29 13:58:06 +00:00
|
|
|
const u32 dataSize = stride * height;
|
|
|
|
|
|
|
|
// Auxiliary frame buffer
|
2015-10-31 02:36:16 +00:00
|
|
|
if (m_width != VI.width && config.frameBufferEmulation.copyAuxToRDRAM == 0) {
|
2015-08-19 17:50:40 +00:00
|
|
|
// 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.
|
|
|
|
const u32 twoPercent = dataSize / 200;
|
|
|
|
u32 start = m_startAddress >> 2;
|
|
|
|
u32 * pData = (u32*)RDRAM;
|
|
|
|
for (u32 i = 0; i < twoPercent; ++i) {
|
|
|
|
if (i < 4)
|
|
|
|
pData[start++] = fingerprint[i];
|
|
|
|
else
|
|
|
|
pData[start++] = 0;
|
2015-04-29 13:58:06 +00:00
|
|
|
}
|
2015-08-19 17:50:40 +00:00
|
|
|
m_cleared = false;
|
|
|
|
m_fingerprint = true;
|
|
|
|
return;
|
2015-04-29 13:58:06 +00:00
|
|
|
}
|
|
|
|
m_RdramCopy.resize(dataSize);
|
|
|
|
memcpy(m_RdramCopy.data(), RDRAM + m_startAddress, dataSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FrameBuffer::isValid() const
|
|
|
|
{
|
2015-10-16 15:42:35 +00:00
|
|
|
if (m_validityChecked == video().getBuffersSwapCount())
|
2015-04-29 13:58:06 +00:00
|
|
|
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;
|
|
|
|
}
|
2015-12-14 18:27:53 +00:00
|
|
|
return wrongPixels < (m_endAddress - m_startAddress) / 400; // threshold level 1% of dwords
|
2015-08-17 15:45:08 +00:00
|
|
|
} else if (m_fingerprint) {
|
2015-07-21 11:32:52 +00:00
|
|
|
//check if our fingerprint is still there
|
|
|
|
u32 start = m_startAddress >> 2;
|
2015-07-21 15:26:35 +00:00
|
|
|
for (u32 i = 0; i < 4; ++i)
|
|
|
|
if ((pData[start++] & 0xFFFEFFFE) != (fingerprint[i] & 0xFFFEFFFE))
|
2015-07-21 11:32:52 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
2015-08-17 15:45:08 +00:00
|
|
|
} else if (!m_RdramCopy.empty()) {
|
2015-04-29 13:58:06 +00:00
|
|
|
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;
|
|
|
|
}
|
2015-12-14 18:27:53 +00:00
|
|
|
return wrongPixels < size / 400; // threshold level 1% of dwords
|
2015-04-29 13:58:06 +00:00
|
|
|
}
|
|
|
|
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()
|
|
|
|
{
|
2015-05-14 13:47:25 +00:00
|
|
|
#ifdef GL_MULTISAMPLING_SUPPORT
|
2015-02-09 12:27:39 +00:00
|
|
|
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;
|
2015-05-14 13:47:25 +00:00
|
|
|
#endif
|
2015-02-09 12:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2015-09-27 04:10:05 +00:00
|
|
|
m_pCopy = NULL;
|
2015-09-24 12:06:07 +00:00
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
2014-09-08 11:01:22 +00:00
|
|
|
}
|
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;
|
2015-09-27 04:10:05 +00:00
|
|
|
m_pCopy = NULL;
|
2015-09-24 12:06:07 +00:00
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
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;
|
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-09-20 14:09:59 +00:00
|
|
|
if (m_pCurrent->m_height != gDP.scissor.lry) {
|
|
|
|
m_pCurrent->reinit((u32)gDP.scissor.lry);
|
2015-03-15 05:31:43 +00:00
|
|
|
|
2015-09-20 14:09:59 +00:00
|
|
|
if (m_pCurrent->_isMarioTennisScoreboard())
|
|
|
|
g_RDRAMtoFB.CopyFromRDRAM(m_pCurrent->m_startAddress + 4, false);
|
|
|
|
gSP.changed |= CHANGED_VIEWPORT;
|
|
|
|
}
|
2015-03-01 06:53:15 +00:00
|
|
|
m_pCurrent->m_needHeightCorrection = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-10-31 02:39:14 +00:00
|
|
|
if (m_pCurrent != NULL && config.frameBufferEmulation.copyAuxToRDRAM != 0) {
|
|
|
|
if (m_pCurrent->m_width != VI.width) {
|
2015-10-31 03:11:33 +00:00
|
|
|
FrameBuffer_CopyToRDRAM(m_pCurrent->m_startAddress, true);
|
2015-10-31 02:39:14 +00:00
|
|
|
removeBuffer(m_pCurrent->m_startAddress);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-20 14:12:52 +00:00
|
|
|
if (VI.width == 0 || _height == 0) {
|
|
|
|
m_pCurrent = NULL;
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
2014-09-27 06:17:01 +00:00
|
|
|
return;
|
2015-09-20 14:12:52 +00:00
|
|
|
}
|
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) {
|
2015-09-20 14:28:05 +00:00
|
|
|
if (m_pCurrent->m_width == VI.width || m_pCurrent->m_needHeightCorrection) {
|
2015-03-19 14:42:09 +00:00
|
|
|
gDP.colorImage.height = min(gDP.colorImage.height, VI.height);
|
2015-09-20 14:28:05 +00:00
|
|
|
m_pCurrent->m_endAddress = min(RDRAMSize, m_pCurrent->m_startAddress + (((m_pCurrent->m_width * gDP.colorImage.height) << m_pCurrent->m_size >> 1) - 1));
|
|
|
|
}
|
2015-08-17 19:18:51 +00:00
|
|
|
if (!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-09-20 14:02:22 +00:00
|
|
|
const u32 endAddress = _address + ((_width * _height) << _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
|
|
|
|
2016-01-02 12:42:50 +00:00
|
|
|
if (m_pCurrent->_isMarioTennisScoreboard())
|
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-12-23 10:21:55 +00:00
|
|
|
m_pCurrent->m_postProcessed = 0;
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
|
2015-10-31 02:36:16 +00:00
|
|
|
void FrameBufferList::copyAux()
|
|
|
|
{
|
|
|
|
for (FrameBuffers::iterator iter = m_list.begin(); iter != m_list.end(); ++iter) {
|
|
|
|
if (iter->m_width != VI.width && iter->m_height != VI.height)
|
2015-10-31 03:11:33 +00:00
|
|
|
FrameBuffer_CopyToRDRAM(iter->m_startAddress, true);
|
2015-10-31 02:36:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBufferList::removeAux()
|
|
|
|
{
|
|
|
|
for (FrameBuffers::iterator iter = m_list.begin(); iter != m_list.end(); ++iter) {
|
|
|
|
while (iter->m_width != VI.width && iter->m_height != VI.height) {
|
|
|
|
if (&(*iter) == m_pCurrent) {
|
|
|
|
m_pCurrent = NULL;
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
}
|
|
|
|
iter = m_list.erase(iter);
|
|
|
|
if (iter == m_list.end())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-09-24 12:06:07 +00:00
|
|
|
if (&(*iter) == m_pCurrent) {
|
2015-02-19 07:01:31 +00:00
|
|
|
m_pCurrent = NULL;
|
2015-09-24 12:06:07 +00:00
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
}
|
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-09-24 12:06:07 +00:00
|
|
|
if (&(*iter) == m_pCurrent) {
|
2015-04-02 09:43:57 +00:00
|
|
|
m_pCurrent = NULL;
|
2015-09-24 12:06:07 +00:00
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
}
|
2015-03-11 11:33:47 +00:00
|
|
|
iter = m_list.erase(iter);
|
|
|
|
if (iter == m_list.end())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-23 12:36:03 +00:00
|
|
|
void FrameBufferList::fillBufferInfo(FrameBufferInfo * _pinfo, u32 _size)
|
|
|
|
{
|
|
|
|
u32 idx = 0;
|
|
|
|
for (FrameBuffers::iterator iter = m_list.begin(); iter != m_list.end(); ++iter) {
|
|
|
|
if (iter->m_width == VI.width && !iter->m_cfb) {
|
|
|
|
_pinfo[idx].addr = iter->m_startAddress;
|
|
|
|
_pinfo[idx].width = iter->m_width;
|
|
|
|
_pinfo[idx].height = iter->m_height;
|
|
|
|
_pinfo[idx++].size = iter->m_size;
|
|
|
|
if (idx >= _size)
|
|
|
|
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-06-02 12:57:54 +00:00
|
|
|
#ifdef GLES2
|
|
|
|
if (pDepthBuffer->m_pDepthBufferTexture->realWidth == m_pCurrent->m_pTexture->realWidth) {
|
|
|
|
#else
|
2015-04-11 17:17:38 +00:00
|
|
|
if (pDepthBuffer->m_pDepthBufferTexture->realWidth >= m_pCurrent->m_pTexture->realWidth) {
|
2015-06-02 12:57:54 +00:00
|
|
|
#endif
|
2015-04-11 17:17:38 +00:00
|
|
|
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()
|
|
|
|
{
|
|
|
|
g_RDRAMtoFB.Destroy();
|
|
|
|
#ifndef GLES2
|
|
|
|
g_dbToRDRAM.Destroy();
|
|
|
|
g_fbToRDRAM.Destroy();
|
|
|
|
#endif
|
|
|
|
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();
|
2015-08-27 13:20:26 +00:00
|
|
|
OGLRender & render = ogl.getRender();
|
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)
|
2015-08-27 13:20:26 +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-08-27 13:20:26 +00:00
|
|
|
#ifdef GLESX
|
|
|
|
if (render.getRenderer() == OGLRender::glrAdreno)
|
|
|
|
dstCoord[0] += 1; // workaround for Adreno's issue with glBindFramebuffer;
|
|
|
|
#endif // GLESX
|
2015-04-03 05:36:31 +00:00
|
|
|
|
2015-08-27 13:20:26 +00:00
|
|
|
render.updateScissor(pBuffer);
|
2015-12-23 10:22:30 +00:00
|
|
|
PostProcessor::get().doGammaCorrection(pBuffer);
|
2015-12-23 10:21:55 +00:00
|
|
|
PostProcessor::get().doBlur(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 };
|
2015-08-27 13:20:26 +00:00
|
|
|
render.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
|
|
|
{
|
2015-06-01 17:58:57 +00:00
|
|
|
if (VI.width == 0 || *REG.VI_WIDTH == 0 || *REG.VI_H_START == 0) // H width is zero. Don't draw
|
2014-04-10 15:44:05 +00:00
|
|
|
return;
|
2015-06-01 17:58:57 +00:00
|
|
|
|
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
|
|
|
|
2015-05-30 16:40:14 +00:00
|
|
|
OGLVideo & ogl = video();
|
|
|
|
ogl.getRender().updateScissor(pBuffer);
|
2015-12-23 10:22:30 +00:00
|
|
|
PostProcessor::get().doGammaCorrection(pBuffer);
|
2015-12-23 10:21:55 +00:00
|
|
|
PostProcessor::get().doBlur(pBuffer);
|
2015-06-01 17:58:57 +00:00
|
|
|
ogl.getRender().dropRenderState();
|
2015-05-30 16:40:14 +00:00
|
|
|
gSP.changed = gDP.changed = 0;
|
|
|
|
|
|
|
|
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_DEPTH_TEST);
|
2014-04-10 15:44:05 +00:00
|
|
|
glDisable( GL_CULL_FACE );
|
|
|
|
glDisable( GL_POLYGON_OFFSET_FILL );
|
|
|
|
|
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
|
|
|
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;
|
2015-07-01 09:20:00 +00:00
|
|
|
gSP.textureTile[0]->shifts = gSP.textureTile[0]->shiftt = 0;
|
2014-09-08 11:01:22 +00:00
|
|
|
currentCombiner()->updateTextureInfo(true);
|
2015-06-23 16:19:11 +00:00
|
|
|
CombinerInfo::get().updateParameters(OGLRender::rsTexRect);
|
2014-04-10 15:44:05 +00:00
|
|
|
|
2015-05-30 16:40:14 +00:00
|
|
|
glScissor(0, 0, ogl.getScreenWidth(), ogl.getScreenHeight() + ogl.getHeightOffset());
|
|
|
|
|
2014-04-10 15:44:05 +00:00
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
2015-06-01 17:58:57 +00:00
|
|
|
|
|
|
|
FrameBuffer * pCurrent = m_pCurrent;
|
|
|
|
m_pCurrent = pBuffer;
|
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);
|
2015-06-01 17:58:57 +00:00
|
|
|
m_pCurrent = pCurrent;
|
2015-05-30 16:40:14 +00:00
|
|
|
|
|
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
|
|
if (m_pCurrent != NULL)
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_pCurrent->m_FBO);
|
2014-09-21 12:15:22 +00:00
|
|
|
ogl.swapBuffers();
|
2015-05-30 16:40:14 +00:00
|
|
|
|
2015-05-07 13:11:54 +00:00
|
|
|
gSP.changed |= CHANGED_VIEWPORT;
|
2015-05-30 16:40:14 +00:00
|
|
|
gDP.changed |= CHANGED_COMBINE | CHANGED_SCISSOR;
|
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
|
|
|
|
2015-11-23 12:36:03 +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
|
|
|
|
2015-06-26 13:20:44 +00:00
|
|
|
static
|
|
|
|
void copyWhiteToRDRAM(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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_pBuffer->m_copiedToRdram = true;
|
|
|
|
_pBuffer->copyRdram();
|
|
|
|
|
|
|
|
_pBuffer->m_cleared = false;
|
|
|
|
}
|
|
|
|
|
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;
|
2015-05-06 13:47:12 +00:00
|
|
|
m_pTexture->frameBufferTexture = CachedTexture::fbOneSample;
|
2013-09-07 16:28:20 +00:00
|
|
|
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 );
|
2015-06-02 12:57:24 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, fboFormats.colorInternalFormat, m_pTexture->realWidth, m_pTexture->realHeight, 0, fboFormats.colorFormat, fboFormats.colorType, 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-10-31 03:11:33 +00:00
|
|
|
glGenBuffers(3, m_PBO);
|
|
|
|
for (u32 i = 0; i < 3; ++i) {
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[i]);
|
|
|
|
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);
|
2015-10-03 17:23:18 +00:00
|
|
|
m_curIndex = 0;
|
2013-09-05 16:24:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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-10-31 03:11:33 +00:00
|
|
|
glDeleteBuffers(3, m_PBO);
|
|
|
|
m_PBO[0] = m_PBO[1] = m_PBO[2] = 0;
|
2013-09-05 16:24:34 +00:00
|
|
|
}
|
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
bool FrameBufferToRDRAM::_prepareCopy(u32 _address)
|
2015-04-04 10:32:17 +00:00
|
|
|
{
|
2015-11-29 18:30:50 +00:00
|
|
|
const u32 curFrame = video().getBuffersSwapCount();
|
|
|
|
if (m_frameCount == curFrame)
|
|
|
|
return true;
|
|
|
|
|
2015-10-31 02:20:20 +00:00
|
|
|
if (VI.width == 0 || frameBufferList().getCurrent() == NULL)
|
2015-11-23 13:03:33 +00:00
|
|
|
return false;
|
2015-10-31 02:20:20 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
m_pCurFrameBuffer = frameBufferList().findBuffer(_address);
|
|
|
|
if (m_pCurFrameBuffer == NULL || m_pCurFrameBuffer->m_isOBScreen)
|
|
|
|
return false;
|
2015-10-31 02:20:20 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
const u32 numPixels = m_pCurFrameBuffer->m_width * m_pCurFrameBuffer->m_height;
|
2015-10-31 02:20:20 +00:00
|
|
|
if (numPixels == 0)
|
2015-11-23 13:03:33 +00:00
|
|
|
return false;
|
2013-08-10 11:12:17 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
const u32 stride = m_pCurFrameBuffer->m_width << m_pCurFrameBuffer->m_size >> 1;
|
|
|
|
const u32 height = _cutHeight(_address, m_pCurFrameBuffer->m_height, stride);
|
2015-11-15 09:26:03 +00:00
|
|
|
if (height == 0)
|
2015-11-23 13:03:33 +00:00
|
|
|
return false;
|
2015-11-15 09:26:03 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
if ((config.generalEmulation.hacks & hack_subscreen) != 0 && m_pCurFrameBuffer->m_width == VI.width && m_pCurFrameBuffer->m_height == VI.height) {
|
|
|
|
copyWhiteToRDRAM(m_pCurFrameBuffer);
|
|
|
|
return false;
|
2015-04-04 10:32:17 +00:00
|
|
|
}
|
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
_address = m_pCurFrameBuffer->m_startAddress;
|
2015-02-13 12:29:15 +00:00
|
|
|
if (config.video.multisampling != 0) {
|
2015-11-23 13:03:33 +00:00
|
|
|
m_pCurFrameBuffer->resolveMultisampledTexture();
|
|
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_pCurFrameBuffer->m_resolveFBO);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_pCurFrameBuffer->m_FBO);
|
2013-09-04 02:15:05 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
if (m_pCurFrameBuffer->m_scaleX > 1.0f) {
|
2015-10-31 02:27:34 +00:00
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO);
|
2015-11-23 13:03:33 +00:00
|
|
|
glScissor(0, 0, m_pCurFrameBuffer->m_pTexture->realWidth, m_pCurFrameBuffer->m_pTexture->realHeight);
|
2015-10-31 02:27:34 +00:00
|
|
|
glBlitFramebuffer(
|
|
|
|
0, 0, video().getWidth(), video().getHeight(),
|
|
|
|
0, 0, VI.width, VI.height,
|
|
|
|
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
|
|
|
);
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferList().getCurrent()->m_FBO);
|
|
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBO);
|
|
|
|
}
|
2015-11-23 13:03:33 +00:00
|
|
|
|
2015-11-29 18:30:50 +00:00
|
|
|
m_frameCount = curFrame;
|
2015-11-23 13:03:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename TSrc, typename TDst>
|
|
|
|
void _writeToRdram(TSrc* _src, TDst* _dst, TDst(*converter)(TSrc _c), TSrc _testValue, u32 _xor, u32 _width, u32 _height, u32 _numPixels, u32 _startAddress, u32 _bufferAddress, u32 _bufferSize)
|
|
|
|
{
|
|
|
|
u32 chunkStart = ((_startAddress - _bufferAddress) >> (_bufferSize - 1)) % _width;
|
|
|
|
if (chunkStart % 2 != 0) {
|
|
|
|
--chunkStart;
|
|
|
|
--_dst;
|
2015-11-29 18:31:59 +00:00
|
|
|
++_numPixels;
|
2015-11-23 13:03:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 numStored = 0;
|
|
|
|
u32 y = 0;
|
|
|
|
TSrc c;
|
|
|
|
if (chunkStart > 0) {
|
|
|
|
for (u32 x = chunkStart; x < _width; ++x) {
|
|
|
|
c = _src[x + (_height - 1)*_width];
|
|
|
|
if (c != _testValue)
|
2015-12-03 18:55:32 +00:00
|
|
|
_dst[numStored ^ _xor] = converter(c);
|
2015-11-23 13:03:33 +00:00
|
|
|
++numStored;
|
|
|
|
}
|
|
|
|
++y;
|
|
|
|
_dst += numStored;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 dsty = 0;
|
|
|
|
for (; y < _height; ++y) {
|
|
|
|
for (u32 x = 0; x < _width && numStored < _numPixels; ++x) {
|
|
|
|
c = _src[x + (_height - y - 1)*_width];
|
|
|
|
if (c != _testValue)
|
|
|
|
_dst[(x + dsty*_width) ^ _xor] = converter(c);
|
|
|
|
++numStored;
|
|
|
|
}
|
|
|
|
++dsty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
u8 FrameBufferToRDRAM::_RGBAtoR8(u8 _c) {
|
|
|
|
return _c;
|
|
|
|
}
|
|
|
|
|
|
|
|
u16 FrameBufferToRDRAM::_RGBAtoRGBA16(u32 _c) {
|
|
|
|
RGBA c;
|
|
|
|
c.raw = _c;
|
|
|
|
return ((c.r >> 3) << 11) | ((c.g >> 3) << 6) | ((c.b >> 3) << 1) | (c.a == 0 ? 0 : 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 FrameBufferToRDRAM::_RGBAtoRGBA32(u32 _c) {
|
|
|
|
RGBA c;
|
|
|
|
c.raw = _c;
|
|
|
|
return (c.r << 24) | (c.g << 16) | (c.b << 8) | c.a;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBufferToRDRAM::_copy(u32 _startAddress, u32 _endAddress, bool _sync)
|
|
|
|
{
|
|
|
|
const u32 stride = m_pCurFrameBuffer->m_width << m_pCurFrameBuffer->m_size >> 1;
|
|
|
|
const u32 max_height = _cutHeight(_startAddress, m_pCurFrameBuffer->m_height, stride);
|
|
|
|
|
|
|
|
u32 numPixels = (_endAddress - _startAddress) >> (m_pCurFrameBuffer->m_size - 1);
|
|
|
|
if (numPixels / m_pCurFrameBuffer->m_width > max_height) {
|
|
|
|
_endAddress = _startAddress + (max_height * stride);
|
|
|
|
numPixels = (_endAddress - _startAddress) >> (m_pCurFrameBuffer->m_size - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
const GLsizei width = m_pCurFrameBuffer->m_width;
|
|
|
|
const GLint x0 = 0;
|
2015-12-03 18:55:32 +00:00
|
|
|
const GLint y0 = max_height - (_endAddress - m_pCurFrameBuffer->m_startAddress) / stride;
|
|
|
|
const GLint y1 = max_height - (_startAddress - m_pCurFrameBuffer->m_startAddress) / stride;
|
2015-12-04 16:49:37 +00:00
|
|
|
const GLsizei height = min(max_height, 1 + y1 - y0);
|
2015-11-23 13:03:33 +00:00
|
|
|
|
|
|
|
GLenum colorFormat, colorType, colorFormatBytes;
|
|
|
|
if (m_pCurFrameBuffer->m_size > G_IM_SIZ_8b) {
|
|
|
|
colorFormat = fboFormats.colorFormat;
|
|
|
|
colorType = fboFormats.colorType;
|
|
|
|
colorFormatBytes = fboFormats.colorFormatBytes;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
colorFormat = fboFormats.monochromeFormat;
|
|
|
|
colorType = fboFormats.monochromeType;
|
|
|
|
colorFormatBytes = fboFormats.monochromeFormatBytes;
|
|
|
|
}
|
|
|
|
|
2014-10-13 12:37:43 +00:00
|
|
|
#ifndef GLES2
|
2015-10-03 17:23:18 +00:00
|
|
|
// If Sync, read pixels from the buffer, copy them to RDRAM.
|
|
|
|
// If not Sync, read pixels from the buffer, copy pixels from the previous buffer to RDRAM.
|
2015-10-31 03:11:33 +00:00
|
|
|
if (!_sync) {
|
|
|
|
m_curIndex ^= 1;
|
2015-11-23 13:03:33 +00:00
|
|
|
const u32 nextIndex = m_curIndex ^ 1;
|
2015-10-31 03:11:33 +00:00
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[m_curIndex]);
|
2015-11-23 13:03:33 +00:00
|
|
|
glReadPixels(x0, y0, width, height, colorFormat, colorType, 0);
|
2015-10-31 03:11:33 +00:00
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[nextIndex]);
|
2015-11-23 13:03:33 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-10-31 03:11:33 +00:00
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[2]);
|
2015-11-23 13:03:33 +00:00
|
|
|
glReadPixels(x0, y0, width, height, colorFormat, colorType, 0);
|
2015-10-31 03:11:33 +00:00
|
|
|
}
|
2015-10-31 02:20:20 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
GLubyte* pixelData = (GLubyte*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width * height * colorFormatBytes, GL_MAP_READ_BIT);
|
2015-10-31 02:20:20 +00:00
|
|
|
if (pixelData == NULL)
|
2013-09-05 16:24:34 +00:00
|
|
|
return;
|
2014-03-21 08:16:36 +00:00
|
|
|
#else
|
2015-11-23 13:03:33 +00:00
|
|
|
GLubyte* pixelData = (GLubyte*)malloc(width * height * colorFormatBytes);
|
2015-10-31 02:20:20 +00:00
|
|
|
if (pixelData == NULL)
|
2014-03-21 08:16:36 +00:00
|
|
|
return;
|
2015-11-23 13:03:33 +00:00
|
|
|
glReadPixels(x0, y0, width, height, colorFormat, colorType, pixelData);
|
2014-03-21 08:16:36 +00:00
|
|
|
#endif // GLES2
|
2013-09-05 16:24:34 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
if (m_pCurFrameBuffer->m_size == G_IM_SIZ_32b) {
|
2013-09-04 02:15:05 +00:00
|
|
|
u32 *ptr_src = (u32*)pixelData;
|
2015-11-23 13:03:33 +00:00
|
|
|
u32 *ptr_dst = (u32*)(RDRAM + _startAddress);
|
|
|
|
_writeToRdram<u32, u32>(ptr_src, ptr_dst, &FrameBufferToRDRAM::_RGBAtoRGBA32, 0, 0, width, height, numPixels, _startAddress, m_pCurFrameBuffer->m_startAddress, m_pCurFrameBuffer->m_size);
|
|
|
|
} else if (m_pCurFrameBuffer->m_size == G_IM_SIZ_16b) {
|
|
|
|
u32 *ptr_src = (u32*)pixelData;
|
|
|
|
u16 *ptr_dst = (u16*)(RDRAM + _startAddress);
|
|
|
|
_writeToRdram<u32, u16>(ptr_src, ptr_dst, &FrameBufferToRDRAM::_RGBAtoRGBA16, 0, 1, width, height, numPixels, _startAddress, m_pCurFrameBuffer->m_startAddress, m_pCurFrameBuffer->m_size);
|
|
|
|
} else if (m_pCurFrameBuffer->m_size == G_IM_SIZ_8b) {
|
|
|
|
u8 *ptr_src = (u8*)pixelData;
|
|
|
|
u8 *ptr_dst = RDRAM + _startAddress;
|
|
|
|
_writeToRdram<u8, u8>(ptr_src, ptr_dst, &FrameBufferToRDRAM::_RGBAtoR8, 0, 3, width, height, numPixels, _startAddress, m_pCurFrameBuffer->m_startAddress, m_pCurFrameBuffer->m_size);
|
2013-08-10 11:12:17 +00:00
|
|
|
}
|
2015-11-23 13:03:33 +00:00
|
|
|
|
|
|
|
m_pCurFrameBuffer->m_copiedToRdram = true;
|
|
|
|
m_pCurFrameBuffer->copyRdram();
|
|
|
|
m_pCurFrameBuffer->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);
|
2015-10-31 03:11:33 +00:00
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
2014-03-21 08:16:36 +00:00
|
|
|
#else
|
|
|
|
free(pixelData);
|
|
|
|
#endif
|
2015-04-03 14:58:45 +00:00
|
|
|
gDP.changed |= CHANGED_SCISSOR;
|
2013-08-10 11:12:17 +00:00
|
|
|
}
|
2015-11-23 13:03:33 +00:00
|
|
|
|
|
|
|
void FrameBufferToRDRAM::copyToRDRAM(u32 _address, bool _sync)
|
|
|
|
{
|
|
|
|
if (!_prepareCopy(_address))
|
|
|
|
return;
|
|
|
|
_copy(m_pCurFrameBuffer->m_startAddress, m_pCurFrameBuffer->m_endAddress, _sync);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBufferToRDRAM::copyChunkToRDRAM(u32 _address)
|
|
|
|
{
|
|
|
|
if (!_prepareCopy(_address))
|
|
|
|
return;
|
|
|
|
_copy(_address, _address + 0x1000, true);
|
|
|
|
}
|
2014-04-10 14:44:07 +00:00
|
|
|
#endif // GLES2
|
2013-08-10 11:12:17 +00:00
|
|
|
|
2015-10-31 03:11:33 +00:00
|
|
|
void FrameBuffer_CopyToRDRAM(u32 _address, bool _sync)
|
2013-06-09 11:55:21 +00:00
|
|
|
{
|
2014-04-10 14:44:07 +00:00
|
|
|
#ifndef GLES2
|
2015-11-23 13:03:33 +00:00
|
|
|
g_fbToRDRAM.copyToRDRAM(_address, _sync);
|
2015-06-26 13:20:44 +00:00
|
|
|
#else
|
|
|
|
if ((config.generalEmulation.hacks & hack_subscreen) == 0)
|
|
|
|
return;
|
|
|
|
if (VI.width == 0 || frameBufferList().getCurrent() == NULL)
|
|
|
|
return;
|
|
|
|
FrameBuffer *pBuffer = frameBufferList().findBuffer(_address);
|
|
|
|
if (pBuffer == NULL || pBuffer->m_width < VI.width || pBuffer->m_isOBScreen)
|
|
|
|
return;
|
|
|
|
copyWhiteToRDRAM(pBuffer);
|
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
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
void FrameBuffer_CopyChunkToRDRAM(u32 _address)
|
|
|
|
{
|
|
|
|
#ifndef GLES2
|
|
|
|
g_fbToRDRAM.copyChunkToRDRAM(_address);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
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;
|
2015-05-06 13:47:12 +00:00
|
|
|
m_pColorTexture->frameBufferTexture = CachedTexture::fbOneSample;
|
2015-02-02 08:56:53 +00:00
|
|
|
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;
|
2015-05-06 13:47:12 +00:00
|
|
|
m_pDepthTexture->frameBufferTexture = CachedTexture::fbOneSample;
|
2015-02-02 08:56:53 +00:00
|
|
|
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-06-02 12:57:24 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, fboFormats.monochromeInternalFormat, m_pColorTexture->realWidth, m_pColorTexture->realHeight, 0, fboFormats.monochromeFormat, fboFormats.monochromeType, 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-06-02 12:57:24 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, fboFormats.depthInternalFormat, m_pDepthTexture->realWidth, m_pDepthTexture->realHeight, 0, GL_DEPTH_COMPONENT, fboFormats.depthType, 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
|
|
|
}
|
2015-07-23 15:55:30 +00:00
|
|
|
if (m_PBO != 0) {
|
|
|
|
glDeleteBuffers(1, &m_PBO);
|
|
|
|
m_PBO = 0;
|
|
|
|
}
|
2013-11-12 08:41:19 +00:00
|
|
|
}
|
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
bool DepthBufferToRDRAM::_prepareCopy(u32 _address)
|
|
|
|
{
|
|
|
|
const u32 curFrame = video().getBuffersSwapCount();
|
|
|
|
if (m_frameCount == curFrame)
|
|
|
|
return true;
|
|
|
|
|
2015-09-20 09:31:39 +00:00
|
|
|
const u32 numPixels = VI.width * VI.height;
|
|
|
|
if (numPixels == 0) // Incorrect buffer size. Don't copy
|
2014-10-18 15:38:32 +00:00
|
|
|
return false;
|
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
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
m_pCurDepthBuffer = pBuffer->m_pDepthBuffer;
|
|
|
|
const u32 address = m_pCurDepthBuffer->m_address;
|
2015-09-20 09:31:39 +00:00
|
|
|
if (address + numPixels * 2 > RDRAMSize)
|
2015-04-01 06:33:28 +00:00
|
|
|
return false;
|
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
const u32 height = _cutHeight(address, min(VI.height, m_pCurDepthBuffer->m_lry), pBuffer->m_width * 2);
|
2015-11-15 09:26:03 +00:00
|
|
|
if (height == 0)
|
|
|
|
return false;
|
|
|
|
|
2015-02-26 12:00:40 +00:00
|
|
|
if (config.video.multisampling == 0)
|
|
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, pBuffer->m_FBO);
|
|
|
|
else {
|
2015-11-23 13:03:33 +00:00
|
|
|
m_pCurDepthBuffer->resolveDepthBufferTexture(pBuffer);
|
2015-02-26 12:00:40 +00:00
|
|
|
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);
|
2015-11-23 13:03:33 +00:00
|
|
|
m_frameCount = curFrame;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
u16 DepthBufferToRDRAM::_FloatToUInt16(f32 _z)
|
|
|
|
{
|
|
|
|
static const u16 * const zLUT = depthBufferList().getZLUT();
|
|
|
|
u32 idx = 0x3FFFF;
|
|
|
|
if (_z < 1.0f) {
|
|
|
|
_z *= 262144.0f;
|
|
|
|
idx = min(0x3FFFFU, u32(floorf(_z + 0.5f)));
|
|
|
|
}
|
|
|
|
return zLUT[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DepthBufferToRDRAM::_copy(u32 _startAddress, u32 _endAddress)
|
|
|
|
{
|
|
|
|
const u32 stride = m_pCurDepthBuffer->m_width << 1;
|
|
|
|
const u32 max_height = _cutHeight(_startAddress, min(VI.height, m_pCurDepthBuffer->m_lry), stride);
|
|
|
|
|
|
|
|
u32 numPixels = (_endAddress - _startAddress) >> 1;
|
|
|
|
if (numPixels / m_pCurDepthBuffer->m_width > max_height) {
|
|
|
|
_endAddress = _startAddress + (max_height * stride);
|
|
|
|
numPixels = (_endAddress - _startAddress) >> 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const GLsizei width = m_pCurDepthBuffer->m_width;
|
|
|
|
const GLint x0 = 0;
|
2015-12-03 18:55:32 +00:00
|
|
|
const GLint y0 = max_height - (_endAddress - m_pCurDepthBuffer->m_address) / stride;
|
|
|
|
const GLint y1 = max_height - (_startAddress - m_pCurDepthBuffer->m_address) / stride;
|
2015-12-04 16:49:37 +00:00
|
|
|
const GLsizei height = min(max_height, 1 + y1 - y0);
|
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-11-23 13:03:33 +00:00
|
|
|
glReadPixels(x0, y0, width, height, fboFormats.depthFormat, fboFormats.depthType, 0);
|
2013-11-12 08:41:19 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
GLubyte* pixelData = (GLubyte*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, width * height * fboFormats.depthFormatBytes, GL_MAP_READ_BIT);
|
|
|
|
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;
|
2015-11-23 13:03:33 +00:00
|
|
|
u16 *ptr_dst = (u16*)(RDRAM + _startAddress);
|
|
|
|
_writeToRdram<f32, u16>(ptr_src, ptr_dst, &DepthBufferToRDRAM::_FloatToUInt16, 2.0f, 1, width, height, numPixels, _startAddress, m_pCurDepthBuffer->m_address, G_IM_SIZ_16b);
|
2013-11-12 08:41:19 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
m_pCurDepthBuffer->m_cleared = false;
|
|
|
|
FrameBuffer * pBuffer = frameBufferList().findBuffer(m_pCurDepthBuffer->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);
|
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
|
|
|
}
|
2015-11-23 13:03:33 +00:00
|
|
|
|
|
|
|
bool DepthBufferToRDRAM::copyToRDRAM( u32 _address)
|
|
|
|
{
|
|
|
|
if (!_prepareCopy(_address))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const u32 endAddress = m_pCurDepthBuffer->m_address + (min(VI.height, m_pCurDepthBuffer->m_lry) * m_pCurDepthBuffer->m_width * 2);
|
|
|
|
return _copy(m_pCurDepthBuffer->m_address, endAddress);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DepthBufferToRDRAM::copyChunkToRDRAM(u32 _address)
|
|
|
|
{
|
|
|
|
if (!_prepareCopy(_address))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const u32 endAddress = _address + 0x1000;
|
|
|
|
return _copy(_address, endAddress);
|
|
|
|
}
|
2014-03-21 08:16:36 +00:00
|
|
|
#endif // GLES2
|
2013-11-12 08:41:19 +00:00
|
|
|
|
2015-11-23 13:03:33 +00:00
|
|
|
bool FrameBuffer_CopyDepthBuffer( u32 address )
|
|
|
|
{
|
2014-03-21 08:16:36 +00:00
|
|
|
#ifndef GLES2
|
2015-09-27 04:10:05 +00:00
|
|
|
FrameBuffer * pCopyBuffer = frameBufferList().getCopyBuffer();
|
|
|
|
if (pCopyBuffer != NULL) {
|
|
|
|
// This code is mainly to emulate Zelda MM camera.
|
2015-11-23 13:03:33 +00:00
|
|
|
g_fbToRDRAM.copyToRDRAM(pCopyBuffer->m_startAddress, true);
|
2015-09-27 04:10:05 +00:00
|
|
|
pCopyBuffer->m_RdramCopy.resize(0); // To disable validity check by RDRAM content. CPU may change content of the buffer for some unknown reason.
|
|
|
|
frameBufferList().setCopyBuffer(NULL);
|
|
|
|
return true;
|
|
|
|
} else
|
2015-11-23 13:03:33 +00:00
|
|
|
return g_dbToRDRAM.copyToRDRAM(address);
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FrameBuffer_CopyDepthBufferChunk(u32 address)
|
|
|
|
{
|
|
|
|
#ifndef GLES2
|
|
|
|
return g_dbToRDRAM.copyChunkToRDRAM(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;
|
2015-05-06 13:47:12 +00:00
|
|
|
m_pTexture->frameBufferTexture = CachedTexture::fbOneSample;
|
2013-09-07 16:31:04 +00:00
|
|
|
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 );
|
2015-06-02 12:57:24 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, fboFormats.colorInternalFormat, m_pTexture->realWidth, m_pTexture->realHeight, 0, fboFormats.colorFormat, fboFormats.colorType, 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
|
2015-07-23 15:55:30 +00:00
|
|
|
if (m_PBO != 0) {
|
|
|
|
glDeleteBuffers(1, &m_PBO);
|
|
|
|
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-11-15 09:26:03 +00:00
|
|
|
const u32 height = _cutHeight(address, pBuffer->m_startAddress == _address ? VI.real_height : pBuffer->m_height, pBuffer->m_width * 2);
|
|
|
|
if (height == 0)
|
|
|
|
return;
|
|
|
|
|
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);
|
|
|
|
}
|
2015-05-06 13:48:40 +00:00
|
|
|
currentCombiner()->updateFBInfo();
|
2015-03-15 05:28:53 +00:00
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
2015-05-18 06:31:27 +00:00
|
|
|
const u32 gdpChanged = gDP.changed & CHANGED_CPU_FB_WRITE;
|
2015-03-15 05:28:53 +00:00
|
|
|
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-05-18 06:31:27 +00:00
|
|
|
gDP.changed |= gdpChanged | 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
|
|
|
}
|