1
0
mirror of https://github.com/blawar/GLideN64.git synced 2024-07-02 09:03:37 +00:00
GLideN64/FrameBuffer.cpp

1095 lines
34 KiB
C++
Raw Normal View History

2013-06-01 13:10:30 +00:00
#include <assert.h>
2015-01-28 13:58:55 +00:00
#include <math.h>
#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"
#include "RSP.h"
#include "RDP.h"
#include "gDP.h"
#include "VI.h"
#include "Textures.h"
#include "Combiner.h"
#include "GLSLCombiner.h"
#include "Types.h"
#include "Config.h"
2013-06-01 13:10:30 +00:00
#include "Debug.h"
#include "PostProcessor.h"
2013-06-01 13:10:30 +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
#ifndef GLES2
class FrameBufferToRDRAM
{
public:
FrameBufferToRDRAM() :
2014-03-21 08:16:36 +00:00
m_FBO(0), m_pTexture(NULL), m_curIndex(0)
{
m_aAddress = 0;
2014-03-21 08:16:36 +00:00
m_aPBO[0] = m_aPBO[1] = 0;
}
void Init();
void Destroy();
void CopyToRDRAM( u32 address, bool bSync );
private:
struct RGBA {
u8 r, g, b, a;
};
2013-09-07 16:28:20 +00:00
GLuint m_FBO;
CachedTexture * m_pTexture;
u32 m_aAddress;
u32 m_curIndex;
2014-03-21 08:16:36 +00:00
GLuint m_aPBO[2];
};
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)
{}
2013-11-12 08:41:19 +00:00
void Init();
void Destroy();
bool CopyToRDRAM( u32 address );
2013-11-12 08:41:19 +00:00
private:
GLuint m_FBO;
GLuint m_PBO;
2015-02-02 08:56:53 +00:00
CachedTexture * m_pColorTexture;
CachedTexture * m_pDepthTexture;
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();
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
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;
2015-02-09 12:27:39 +00:00
FrameBuffer::FrameBuffer() : m_cleared(false), m_pLoadTile(NULL), m_pDepthBuffer(NULL), m_pResolveTexture(NULL), m_resolveFBO(0), m_resolved(false)
{
m_pTexture = textureCache().addFrameBufferTexture();
glGenFramebuffers(1, &m_FBO);
}
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),
m_scaleX(_other.m_scaleX), m_scaleY(_other.m_scaleY), m_cleared(_other.m_cleared), m_cfb(_other.m_cfb),
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),
m_pResolveTexture(_other.m_pResolveTexture), m_resolveFBO(_other.m_resolveFBO), m_resolved(_other.m_resolved)
{
_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;
}
FrameBuffer::~FrameBuffer()
{
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)
{
_pTexture->width = (u32)(m_width * video().getScaleX());
_pTexture->height = (u32)(m_height * video().getScaleY());
_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);
}
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;
_initTexture(_format, _size, m_pTexture);
glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
if (config.video.multisampling != 0) {
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_pTexture->glName);
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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_pTexture->glName, 0);
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
_setAndAttachTexture(_size, m_pTexture);
}
void FrameBuffer::resolveMultisampledTexture()
{
if (m_resolved)
return;
glDisable(GL_SCISSOR_TEST);
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);
glEnable(GL_SCISSOR_TEST);
m_resolved = true;
}
CachedTexture * FrameBuffer::getTexture()
{
if (config.video.multisampling == 0)
return m_pTexture;
if (m_resolved)
return m_pResolveTexture;
resolveMultisampledTexture();
return m_pResolveTexture;
}
void FrameBufferList::init()
{
m_pCurrent = NULL;
}
void FrameBufferList::destroy() {
m_list.clear();
m_pCurrent = NULL;
m_drawBuffer = GL_BACK;
}
FrameBuffer * FrameBufferList::findBuffer(u32 _startAddress)
{
for (FrameBuffers::iterator iter = m_list.begin(); iter != m_list.end(); ++iter)
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());
return NULL;
}
FrameBuffer * FrameBufferList::findTmpBuffer(u32 _address)
{
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;
}
void FrameBufferList::saveBuffer(u32 _address, u16 _format, u16 _size, u16 _width, u16 _height, bool _cfb)
{
if (VI.width == 0 || VI.height == 0) // H width is zero. Don't save
return;
OGLVideo & ogl = video();
m_drawBuffer = GL_FRAMEBUFFER;
if (m_pCurrent != NULL && gDP.colorImage.height > 0) {
m_pCurrent->m_endAddress = min(RDRAMSize, m_pCurrent->m_startAddress + (((m_pCurrent->m_width * gDP.colorImage.height) << m_pCurrent->m_size >> 1) - 1));
if (!config.frameBufferEmulation.copyToRDRAM && !config.frameBufferEmulation.copyFromRDRAM && !m_pCurrent->m_cfb && !m_pCurrent->m_cleared && gDP.colorImage.height > 1)
gDPFillRDRAM(m_pCurrent->m_startAddress, 0, 0, m_pCurrent->m_width, gDP.colorImage.height, m_pCurrent->m_width, m_pCurrent->m_size, m_pCurrent->m_fillcolor, false);
}
const u32 endAddress = _address + ((_width * (_height - 1)) << _size >> 1) - 1;
if (m_pCurrent == NULL || m_pCurrent->m_startAddress != _address || m_pCurrent->m_width != _width)
m_pCurrent = _findBuffer(_address, endAddress, _width);
if (m_pCurrent != NULL) {
if ((m_pCurrent->m_startAddress != _address) ||
(m_pCurrent->m_width != _width) ||
//(current->height != height) ||
//(current->size != size) || // TODO FIX ME
(m_pCurrent->m_scaleX != ogl.getScaleX()) ||
(m_pCurrent->m_scaleY != ogl.getScaleY()))
{
removeBuffer(m_pCurrent->m_startAddress);
m_pCurrent = NULL;
} else {
2015-02-09 12:27:39 +00:00
m_pCurrent->m_resolved = false;
glBindFramebuffer(GL_FRAMEBUFFER, m_pCurrent->m_FBO);
if (m_pCurrent->m_size != _size) {
f32 fillColor[4];
gDPGetFillColor(fillColor);
ogl.getRender().clearColorBuffer(fillColor);
m_pCurrent->m_size = _size;
m_pCurrent->m_pTexture->format = _format;
m_pCurrent->m_pTexture->size = _size;
}
}
}
const bool bNew = m_pCurrent == NULL;
if (bNew) {
// Wasn't found or removed, create a new one
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);
m_pCurrent = &buffer;
2013-06-04 16:05:09 +00:00
}
2013-06-01 13:10:30 +00:00
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
// HACK ALERT: Dirty hack for Mario Tennis score board
if (bNew && (m_pCurrent->m_startAddress == 0x13ba50 || m_pCurrent->m_startAddress == 0x264430))
g_RDRAMtoFB.CopyFromRDRAM(m_pCurrent->m_startAddress, false);
if (!_cfb)
*(u32*)&RDRAM[m_pCurrent->m_startAddress] = m_pCurrent->m_startAddress;
m_pCurrent->m_cleared = false;
m_pCurrent->m_isDepthBuffer = false;
gSP.changed |= CHANGED_TEXTURE;
}
void FrameBufferList::removeBuffer(u32 _address )
{
for (FrameBuffers::iterator iter = m_list.begin(); iter != m_list.end(); ++iter)
if (iter->m_startAddress == _address) {
if (m_pCurrent != NULL && m_pCurrent->m_startAddress == _address)
m_pCurrent = NULL;
m_list.erase(iter);
return;
}
}
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);
2014-09-08 11:00:13 +00:00
m_pCurrent->m_pDepthBuffer = pDepthBuffer;
2015-01-27 16:00:06 +00:00
pDepthBuffer->setDepthAttachment();
if (video().getRender().isImageTexturesSupported() && config.frameBufferEmulation.N64DepthCompare != 0)
2015-01-27 16:00:06 +00:00
pDepthBuffer->bindDepthImageTexture();
} else
m_pCurrent->m_pDepthBuffer = NULL;
2015-01-27 16:00:06 +00:00
#ifndef GLES2
2015-01-27 16:00:06 +00:00
GLuint attachments[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, attachments);
#endif
2015-01-27 16:00:06 +00:00
assert(checkFBO());
2013-10-30 06:07:24 +00:00
}
void FrameBuffer_Init()
{
frameBufferList().init();
#ifndef GLES2
g_fbToRDRAM.Init();
g_dbToRDRAM.Init();
#endif
g_RDRAMtoFB.Init();
}
void FrameBuffer_Destroy()
{
g_RDRAMtoFB.Destroy();
#ifndef GLES2
g_dbToRDRAM.Destroy();
g_fbToRDRAM.Destroy();
#endif
frameBufferList().destroy();
}
#ifndef GLES2
void FrameBufferList::renderBuffer(u32 _address)
{
static s32 vStartPrev = 0;
if (VI.width == 0 || *REG.VI_WIDTH == 0) // H width is zero. Don't draw
return;
FrameBuffer *pBuffer = findBuffer(_address);
if (pBuffer == NULL)
return;
OGLVideo & ogl = video();
GLint srcY0, srcY1, dstY0, dstY1;
GLint X0, X1, Xwidth;
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);
const s32 hEnd = _SHIFTR(*REG.VI_H_START, 0, 10);
const s32 hStart = _SHIFTR(*REG.VI_H_START, 16, 10);
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);
bool isLowerField = false;
if (interlaced)
isLowerField = vStart > vStartPrev;
vStartPrev = vStart;
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)
--srcY0;
2014-11-29 13:01:27 +00:00
if (dstY0 > 0)
--dstY0;
}
if (srcY0 + vCurrentHeight > vFullHeight) {
dstPartHeight = srcY0;
srcY0 = (GLint)(srcY0*yScale);
srcPartHeight = srcY0;
srcY1 = VI.real_height;
dstY1 = dstY0 + vCurrentHeight - dstPartHeight;
} else {
dstY0 += srcY0;
dstY1 = dstY0 + vCurrentHeight;
srcY0 = (GLint)(srcY0*yScale);
srcY1 = srcY0 + VI.real_height;
}
const f32 scaleX = _FIXED2FLOAT(_SHIFTR(*REG.VI_X_SCALE, 0, 12), 10);
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
PostProcessor::get().process(pBuffer);
// glDisable(GL_SCISSOR_TEST) does not affect glBlitFramebuffer, at least on AMD
2014-10-02 03:42:18 +00:00
glScissor(0, 0, ogl.getScreenWidth(), ogl.getScreenHeight());
glDisable(GL_SCISSOR_TEST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, pBuffer->m_FBO);
2014-03-21 09:38:39 +00:00
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2014-03-21 08:16:36 +00:00
//glDrawBuffer( GL_BACK );
float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
ogl.getRender().clearColorBuffer(clearColor);
const float srcScaleY = ogl.getScaleY();
const GLint hOffset = (ogl.getScreenWidth() - ogl.getWidth()) / 2;
GLint vOffset = (ogl.getScreenHeight() - ogl.getHeight()) / 2;
if (!ogl.isFullscreen())
vOffset += ogl.getHeightOffset();
2015-02-09 12:27:39 +00:00
GLint srcCoord[4] = { 0, (GLint)(srcY0*srcScaleY), Xwidth, (GLint)(srcY1*srcScaleY) };
GLint dstCoord[4] = { X0 + hOffset, vOffset + (GLint)(dstY0*dstScaleY), hOffset + X1, vOffset + (GLint)(dstY1*dstScaleY) };
2015-02-09 12:27:39 +00:00
GLenum filter = GL_LINEAR;
if (config.video.multisampling != 0) {
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);
} else
filter = GL_NEAREST;
}
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
);
if (dstPartHeight > 0) {
const u32 size = *REG.VI_STATUS & 3;
pBuffer = findBuffer(_address + (((*REG.VI_WIDTH)*VI.height)<<size>>1));
if (pBuffer != NULL) {
srcY0 = 0;
srcY1 = srcPartHeight;
dstY0 = dstY1;
dstY1 = dstY0 + dstPartHeight;
glBindFramebuffer(GL_READ_FRAMEBUFFER, pBuffer->m_FBO);
2014-03-21 09:38:39 +00:00
glBlitFramebuffer(
0, (GLint)(srcY0*srcScaleY), ogl.getWidth(), (GLint)(srcY1*srcScaleY),
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
);
}
}
glEnable(GL_SCISSOR_TEST);
2014-03-21 09:38:39 +00:00
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_pCurrent->m_FBO);
ogl.swapBuffers();
gDP.changed |= CHANGED_SCISSOR;
}
#else
void FrameBufferList::renderBuffer(u32 _address)
{
if (VI.width == 0) // H width is zero. Don't draw
return;
FrameBuffer *pBuffer = findBuffer(_address);
if (pBuffer == NULL)
return;
2013-06-01 13:10:30 +00:00
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_SCISSOR_TEST);
glDisable(GL_DEPTH_TEST);
glDisable( GL_CULL_FACE );
glDisable( GL_POLYGON_OFFSET_FILL );
gSP.changed = gDP.changed = 0;
const u32 width = pBuffer->m_width;
const u32 height = pBuffer->m_height;
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;
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);
gSP.textureTile[0]->fuls = gSP.textureTile[0]->fult = 0.0f;
currentCombiner()->updateTextureInfo(true);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
m_drawBuffer = GL_BACK;
OGLRender::TexturedRectParams params(0.0f, 0.0f, width, height, 0.0f, 0.0f, width - 1.0f, height - 1.0f, false);
ogl.getRender().drawTexturedRect(params);
ogl.swapBuffers();
m_drawBuffer = GL_FRAMEBUFFER;
glEnable(GL_SCISSOR_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, m_pCurrent->m_FBO);
gSP.changed |= CHANGED_TEXTURE | CHANGED_VIEWPORT;
gDP.changed |= CHANGED_COMBINE;
}
#endif
2013-06-01 13:10:30 +00:00
void FrameBuffer_ActivateBufferTexture(s16 t, FrameBuffer *pBuffer)
{
if (pBuffer == NULL || pBuffer->m_pTexture == NULL)
return;
2015-02-09 12:27:39 +00:00
CachedTexture *pTexture = pBuffer->getTexture();
pTexture->scaleS = video().getScaleX() / (float)pTexture->realWidth;
pTexture->scaleT = video().getScaleY() / (float)pTexture->realHeight;
if (gSP.textureTile[t]->shifts > 10)
2015-02-09 12:27:39 +00:00
pTexture->shiftScaleS = (float)(1 << (16 - gSP.textureTile[t]->shifts));
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);
else
2015-02-09 12:27:39 +00:00
pTexture->shiftScaleS = 1.0f;
if (gSP.textureTile[t]->shiftt > 10)
2015-02-09 12:27:39 +00:00
pTexture->shiftScaleT = (float)(1 << (16 - gSP.textureTile[t]->shiftt));
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);
else
2015-02-09 12:27:39 +00:00
pTexture->shiftScaleT = 1.0f;
const u32 shift = gSP.textureTile[t]->imageAddress - pBuffer->m_startAddress;
const u32 factor = pBuffer->m_width << pBuffer->m_size >> 1;
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));
}
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);
}
// frameBufferList().renderBuffer(pBuffer->m_startAddress);
2015-02-09 12:27:39 +00:00
textureCache().activateTexture(t, pTexture);
gDP.changed |= CHANGED_FB_TEXTURE;
}
void FrameBuffer_ActivateBufferTextureBG(s16 t, FrameBuffer *pBuffer )
{
2015-02-09 12:27:39 +00:00
if (pBuffer == NULL || pBuffer->m_pTexture == NULL)
return;
2015-02-09 12:27:39 +00:00
CachedTexture *pTexture = pBuffer->getTexture();
pTexture->scaleS = video().getScaleX() / (float)pTexture->realWidth;
pTexture->scaleT = video().getScaleY() / (float)pTexture->realHeight;
pTexture->shiftScaleS = 1.0f;
pTexture->shiftScaleT = 1.0f;
2015-02-09 12:27:39 +00:00
pTexture->offsetS = gSP.bgImage.imageX;
pTexture->offsetT = (float)pBuffer->m_height - gSP.bgImage.imageY;
// FrameBuffer_RenderBuffer(buffer->startAddress);
2015-02-09 12:27:39 +00:00
textureCache().activateTexture(t, pTexture);
gDP.changed |= CHANGED_FB_TEXTURE;
}
#ifndef GLES2
void FrameBufferToRDRAM::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-09-07 16:28:20 +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;
m_pTexture->realWidth = 1024;
m_pTexture->realHeight = 512;
m_pTexture->textureBytes = m_pTexture->realWidth * m_pTexture->realHeight * 4;
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);
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
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_pTexture->glName, 0);
// check if everything is OK
assert(checkFBO());
2014-03-21 09:38:39 +00:00
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// Generate and initialize Pixel Buffer Objects
glGenBuffers(2, m_aPBO);
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_aPBO[0]);
glBufferData(GL_PIXEL_PACK_BUFFER, 640*480*4, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_aPBO[1]);
glBufferData(GL_PIXEL_PACK_BUFFER, 640*480*4, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
void FrameBufferToRDRAM::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;
if (m_pTexture != NULL) {
textureCache().removeFrameBufferTexture(m_pTexture);
m_pTexture = NULL;
}
2013-09-07 16:28:20 +00:00
glDeleteBuffers(2, m_aPBO);
2013-11-18 03:30:20 +00:00
m_aPBO[0] = m_aPBO[1] = 0;
m_curIndex = 0;
m_aAddress = 0;
}
void FrameBufferToRDRAM::CopyToRDRAM( u32 address, bool bSync ) {
if (VI.width == 0) // H width is zero. Don't copy
return;
FrameBuffer *pBuffer = frameBufferList().findBuffer(address);
if (pBuffer == NULL)
return;
address = pBuffer->m_startAddress;
if (config.video.multisampling != 0) {
pBuffer->resolveMultisampledTexture();
glBindFramebuffer(GL_READ_FRAMEBUFFER, pBuffer->m_resolveFBO);
} else
glBindFramebuffer(GL_READ_FRAMEBUFFER, pBuffer->m_FBO);
glDisable(GL_SCISSOR_TEST);
glReadBuffer(GL_COLOR_ATTACHMENT0);
2014-03-21 09:38:39 +00:00
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO);
glBlitFramebuffer(
0, 0, video().getWidth(), video().getHeight(),
0, 0, pBuffer->m_width, pBuffer->m_height,
GL_COLOR_BUFFER_BIT, GL_LINEAR
);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferList().getCurrent()->m_FBO);
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);
#ifndef GLES2
// 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.
if (m_aAddress == 0)
bSync = true;
m_curIndex = (m_curIndex + 1) % 2;
const u32 nextIndex = bSync ? m_curIndex : (m_curIndex + 1) % 2;
m_aAddress = address;
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_aPBO[m_curIndex]);
glReadPixels( 0, 0, VI.width, VI.height, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_aPBO[nextIndex]);
GLubyte* pixelData = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
if(pixelData == NULL) {
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
return;
}
2014-03-21 08:16:36 +00:00
#else
m_curIndex = 0;
m_aAddress = address;
2014-03-21 08:16:36 +00:00
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
if (pBuffer->m_size == G_IM_SIZ_32b) {
u32 *ptr_dst = (u32*)(RDRAM + m_aAddress);
u32 *ptr_src = (u32*)pixelData;
for (u32 y = 0; y < VI.height; ++y) {
for (u32 x = 0; x < VI.width; ++x)
ptr_dst[x + y*VI.width] = ptr_src[x + (VI.height - y - 1)*VI.width];
}
} else {
u16 *ptr_dst = (u16*)(RDRAM + m_aAddress);
RGBA * ptr_src = (RGBA*)pixelData;
for (u32 y = 0; y < VI.height; ++y) {
for (u32 x = 0; x < VI.width; ++x) {
const RGBA & c = ptr_src[x + (VI.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);
}
}
}
#if 1 //ndef GLES2
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
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);
glEnable(GL_SCISSOR_TEST);
}
#endif // GLES2
void FrameBuffer_CopyToRDRAM( u32 address, bool bSync )
{
#ifndef GLES2
g_fbToRDRAM.CopyToRDRAM(address, bSync);
#endif
}
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;
m_pColorTexture->realHeight = 480;
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;
m_pDepthTexture->realHeight = 480;
m_pDepthTexture->textureBytes = m_pDepthTexture->realWidth * m_pDepthTexture->realHeight * sizeof(float);
textureCache().addFrameBufferTextureSize(m_pDepthTexture->textureBytes);
glBindTexture( GL_TEXTURE_2D, m_pColorTexture->glName );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_pColorTexture->realWidth, m_pColorTexture->realHeight, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
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 );
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 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
glGenBuffers(1, &m_PBO);
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO);
2015-01-28 13:58:55 +00:00
glBufferData(GL_PIXEL_PACK_BUFFER, 640*480*sizeof(float), NULL, GL_DYNAMIC_DRAW);
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;
}
glDeleteBuffers(1, &m_PBO);
m_PBO = 0;
2013-11-12 08:41:19 +00:00
}
bool DepthBufferToRDRAM::CopyToRDRAM( u32 _address) {
if (VI.width == 0) // H width is zero. Don't copy
return false;
if (m_lastDList == RSP.DList) // Already read;
return false;
FrameBuffer *pBuffer = frameBufferList().findBuffer(_address);
if (pBuffer == NULL || pBuffer->m_pDepthBuffer == NULL || !pBuffer->m_pDepthBuffer->m_cleared)
return false;
2013-11-12 08:41:19 +00:00
m_lastDList = RSP.DList;
DepthBuffer * pDepthBuffer = pBuffer->m_pDepthBuffer;
const u32 address = pDepthBuffer->m_address;
2015-01-28 13:58:55 +00:00
glBindFramebuffer(GL_READ_FRAMEBUFFER, pBuffer->m_FBO);
2014-03-21 09:38:39 +00:00
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO);
glDisable(GL_SCISSOR_TEST);
2014-03-21 09:38:39 +00:00
glBlitFramebuffer(
0, 0, video().getWidth(), video().getHeight(),
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
);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferList().getCurrent()->m_FBO);
2013-11-12 08:41:19 +00:00
glBindBuffer(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
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO);
2013-11-12 08:41:19 +00:00
GLubyte* pixelData = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
if(pixelData == NULL) {
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
return false;
2013-11-12 08:41:19 +00:00
}
2015-01-28 13:58:55 +00:00
f32 * ptr_src = (f32*)pixelData;
u16 *ptr_dst = (u16*)(RDRAM + address);
const f32 scale = gSP.viewport.vscale[2] * 32768.0f;
const f32 trans = gSP.viewport.vtrans[2] * 32768.0f;
const u16 * const zLUT = depthBufferList().getZLUT();
2013-11-12 08:41:19 +00:00
for (u32 y = 0; y < VI.height; ++y) {
2013-11-12 08:41:19 +00:00
for (u32 x = 0; x < VI.width; ++x) {
f32 z = ptr_src[x + (VI.height - y - 1)*VI.width];
2015-01-28 13:58:55 +00:00
if (z == 1.0f)
ptr_dst[(x + y*VI.width) ^ 1] = zLUT[0x3FFFF];
else {
z = z*2.0f - 1.0f;
z = (z*scale + trans) * 8.0f;
const u32 idx = min(0x3FFFFU, u32(floorf(z + 0.5f)));
ptr_dst[(x + y*VI.width) ^ 1] = zLUT[idx];
}
2013-11-12 08:41:19 +00:00
}
}
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
2014-03-21 09:38:39 +00:00
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glEnable(GL_SCISSOR_TEST);
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
bool FrameBuffer_CopyDepthBuffer( u32 address ) {
2014-03-21 08:16:36 +00:00
#ifndef GLES2
return g_dbToRDRAM.CopyToRDRAM(address);
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()
{
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;
m_pTexture->realWidth = 1024;
m_pTexture->realHeight = 512;
m_pTexture->textureBytes = m_pTexture->realWidth * m_pTexture->realHeight * 4;
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()
{
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
}
void RDRAMtoFrameBuffer::CopyFromRDRAM( u32 _address, bool _bUseAlpha)
2013-09-07 16:31:04 +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;
if (pBuffer->m_startAddress == _address && gDP.colorImage.changed != 0)
return;
2013-09-07 16:31:04 +00:00
const u32 address = pBuffer->m_startAddress;
const u32 width = pBuffer->m_width;
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
2013-09-07 16:31:04 +00:00
PBOBinder binder(m_PBO);
glBufferData(GL_PIXEL_UNPACK_BUFFER, dataSize, NULL, GL_DYNAMIC_DRAW);
GLubyte* ptr = (GLubyte*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
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;
u8 * image = RDRAM + address;
2013-09-07 16:31:04 +00:00
u32 * dst = (u32*)ptr;
u32 empty = 0;
u32 r, g, b,a, idx;
if (pBuffer->m_size == G_IM_SIZ_16b) {
2013-09-07 16:31:04 +00:00
u16 * src = (u16*)image;
u16 col;
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];
if (_bUseAlpha)
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;
2014-09-30 10:09:40 +00:00
a = (col&1) > 0 ? 0xff : 0;
2013-09-07 16:31:04 +00:00
dst[x + y*width] = (a<<24)|(b<<16)|(g<<8)|r;
}
}
} else {
// 32 bit
u32 * src = (u32*)image;
u32 col;
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];
if (_bUseAlpha)
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;
a = col & 0xff;
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
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);
2013-09-07 16:31:04 +00:00
glDisable( GL_CULL_FACE );
const u32 gspChanged = gSP.changed & CHANGED_CPU_FB_WRITE;
gSP.changed = gDP.changed = 0;
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;
textureCache().activateTexture(0, m_pTexture);
2013-09-07 16:31:04 +00:00
OGLRender::TexturedRectParams params(0.0f, 0.0f, (float)width, (float)height, 0.0f, 0.0f, width - 1.0f, height - 1.0f, false);
video().getRender().drawTexturedRect(params);
gSP.changed |= gspChanged | CHANGED_TEXTURE | CHANGED_VIEWPORT;
2013-09-07 16:31:04 +00:00
gDP.changed |= CHANGED_COMBINE;
}
void FrameBuffer_CopyFromRDRAM( u32 address, bool bUseAlpha )
2013-09-07 16:31:04 +00:00
{
g_RDRAMtoFB.CopyFromRDRAM(address, bUseAlpha);
2013-09-07 16:31:04 +00:00
}