1
0
mirror of https://github.com/blawar/GLideN64.git synced 2024-07-07 03:13:49 +00:00

Fix PBOs in Android

This commit is contained in:
Francisco Zurita 2016-06-04 12:56:09 -04:00 committed by Sergey Lipskiy
parent 8c632ca0ad
commit 87c93d9491
4 changed files with 136 additions and 38 deletions

View File

@ -9,6 +9,7 @@
#include <Config.h> #include <Config.h>
#include <N64.h> #include <N64.h>
#include <VI.h> #include <VI.h>
#include <Log.h>
ColorBufferToRDRAM::ColorBufferToRDRAM() ColorBufferToRDRAM::ColorBufferToRDRAM()
: m_FBO(0) : m_FBO(0)
@ -16,7 +17,12 @@ ColorBufferToRDRAM::ColorBufferToRDRAM()
, m_pCurFrameBuffer(nullptr) , m_pCurFrameBuffer(nullptr)
, m_frameCount(-1) , m_frameCount(-1)
, m_startAddress(-1) , m_startAddress(-1)
, m_lastVIWidth(-1)
, m_lastVIHeight(-1)
{ {
m_allowedRealWidths[0] = 320;
m_allowedRealWidths[1] = 480;
m_allowedRealWidths[2] = 640;
} }
ColorBufferToRDRAM::~ColorBufferToRDRAM() ColorBufferToRDRAM::~ColorBufferToRDRAM()
@ -30,6 +36,22 @@ void ColorBufferToRDRAM::init()
// generate a framebuffer // generate a framebuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glGenFramebuffers(1, &m_FBO); glGenFramebuffers(1, &m_FBO);
_init();
}
void ColorBufferToRDRAM::destroy() {
_destroyFBTexure();
_destroy();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
if (m_FBO != 0) {
glDeleteFramebuffers(1, &m_FBO);
m_FBO = 0;
}
}
void ColorBufferToRDRAM::_initFBTexture(void)
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO);
m_pTexture = textureCache().addFrameBufferTexture(); m_pTexture = textureCache().addFrameBufferTexture();
@ -41,8 +63,10 @@ void ColorBufferToRDRAM::init()
m_pTexture->maskT = 0; m_pTexture->maskT = 0;
m_pTexture->mirrorS = 0; m_pTexture->mirrorS = 0;
m_pTexture->mirrorT = 0; m_pTexture->mirrorT = 0;
m_pTexture->realWidth = 640; //The actual VI width is not used for texture width because most texture widths
m_pTexture->realHeight = 580; //cause slowdowns in the glReadPixels call, at least on Android
m_pTexture->realWidth = _getRealWidth(m_lastVIWidth);
m_pTexture->realHeight = m_lastVIHeight;
m_pTexture->textureBytes = m_pTexture->realWidth * m_pTexture->realHeight * 4; m_pTexture->textureBytes = m_pTexture->realWidth * m_pTexture->realHeight * 4;
textureCache().addFrameBufferTextureSize(m_pTexture->textureBytes); textureCache().addFrameBufferTextureSize(m_pTexture->textureBytes);
glBindTexture(GL_TEXTURE_2D, m_pTexture->glName); glBindTexture(GL_TEXTURE_2D, m_pTexture->glName);
@ -56,20 +80,16 @@ void ColorBufferToRDRAM::init()
assert(checkFBO()); assert(checkFBO());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// _init(m_pTexture->realWidth, m_pTexture->realHeight, m_pTexture->textureBytes); _initBuffers();
_init();
} }
void ColorBufferToRDRAM::destroy() { void ColorBufferToRDRAM::_destroyFBTexure(void)
_destroy(); {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); _destroyBuffers();
if (m_FBO != 0) {
glDeleteFramebuffers(1, &m_FBO); if (m_pTexture != nullptr) {
m_FBO = 0;
}
if (m_pTexture != NULL) {
textureCache().removeFrameBufferTexture(m_pTexture); textureCache().removeFrameBufferTexture(m_pTexture);
m_pTexture = NULL; m_pTexture = nullptr;
} }
} }
@ -97,6 +117,16 @@ bool ColorBufferToRDRAM::_prepareCopy(u32 _startAddress)
if (height == 0) if (height == 0)
return false; return false;
if(m_pTexture == nullptr ||
(m_lastVIWidth != VI.width || m_lastVIHeight != VI.height))
{
_destroyFBTexure();
m_lastVIWidth = VI.width;
m_lastVIHeight = VI.height;
_initFBTexture();
}
m_pCurFrameBuffer = pBuffer; m_pCurFrameBuffer = pBuffer;
if ((config.generalEmulation.hacks & hack_subscreen) != 0 && m_pCurFrameBuffer->m_width == VI.width && m_pCurFrameBuffer->m_height == VI.height) { if ((config.generalEmulation.hacks & hack_subscreen) != 0 && m_pCurFrameBuffer->m_width == VI.width && m_pCurFrameBuffer->m_height == VI.height) {
@ -204,6 +234,17 @@ void ColorBufferToRDRAM::_copy(u32 _startAddress, u32 _endAddress, bool _sync)
gDP.changed |= CHANGED_SCISSOR; gDP.changed |= CHANGED_SCISSOR;
} }
u32 ColorBufferToRDRAM::_getRealWidth(u32 _viWidth)
{
u32 index = 0;
while(index < m_allowedRealWidths.size() && _viWidth > m_allowedRealWidths[index])
{
++index;
}
return m_allowedRealWidths[index];
}
void ColorBufferToRDRAM::copyToRDRAM(u32 _address, bool _sync) void ColorBufferToRDRAM::copyToRDRAM(u32 _address, bool _sync)
{ {
if (!_prepareCopy(_address)) if (!_prepareCopy(_address))

View File

@ -2,6 +2,7 @@
#define ColorBufferToRDRAM_H #define ColorBufferToRDRAM_H
#include <OpenGL.h> #include <OpenGL.h>
#include <array>
struct CachedTexture; struct CachedTexture;
struct FrameBuffer; struct FrameBuffer;
@ -27,6 +28,8 @@ protected:
private: private:
virtual void _init() = 0; virtual void _init() = 0;
virtual void _destroy() = 0; virtual void _destroy() = 0;
virtual void _initBuffers(void) = 0;
virtual void _destroyBuffers(void) = 0;
virtual GLubyte* _getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) = 0; virtual GLubyte* _getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) = 0;
virtual void _cleanUpPixels(GLubyte* pixelData) = 0; virtual void _cleanUpPixels(GLubyte* pixelData) = 0;
@ -37,10 +40,16 @@ private:
u32 raw; u32 raw;
}; };
void _initFBTexture(void);
void _destroyFBTexure(void);
bool _prepareCopy(u32 _startAddress); bool _prepareCopy(u32 _startAddress);
void _copy(u32 _startAddress, u32 _endAddress, bool _sync); void _copy(u32 _startAddress, u32 _endAddress, bool _sync);
u32 _getRealWidth(u32 _viWidth);
// Convert pixel from video memory to N64 buffer format. // Convert pixel from video memory to N64 buffer format.
static u8 _RGBAtoR8(u8 _c); static u8 _RGBAtoR8(u8 _c);
static u16 _RGBAtoRGBA16(u32 _c); static u16 _RGBAtoRGBA16(u32 _c);
@ -50,6 +59,11 @@ private:
FrameBuffer * m_pCurFrameBuffer; FrameBuffer * m_pCurFrameBuffer;
u32 m_frameCount; u32 m_frameCount;
u32 m_startAddress; u32 m_startAddress;
u32 m_lastVIWidth;
u32 m_lastVIHeight;
std::array<u32, 3> m_allowedRealWidths;
}; };
void copyWhiteToRDRAM(FrameBuffer * _pBuffer); void copyWhiteToRDRAM(FrameBuffer * _pBuffer);

View File

@ -24,6 +24,8 @@ private:
void _destroy() override; void _destroy() override;
GLubyte* _getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) override; GLubyte* _getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) override;
void _cleanUpPixels(GLubyte* pixelData) override; void _cleanUpPixels(GLubyte* pixelData) override;
void _initBuffers(void) override;
void _destroyBuffers(void) override;
GraphicBuffer* m_window; GraphicBuffer* m_window;
EGLImageKHR m_image; EGLImageKHR m_image;
@ -37,25 +39,39 @@ ColorBufferToRDRAM & ColorBufferToRDRAM::get()
} }
ColorBufferToRDRAMAndroid::ColorBufferToRDRAMAndroid() ColorBufferToRDRAMAndroid::ColorBufferToRDRAMAndroid()
: ColorBufferToRDRAM() : ColorBufferToRDRAM(),
m_window(nullptr),
m_image(0)
{ {
} }
void ColorBufferToRDRAMAndroid::_init() void ColorBufferToRDRAMAndroid::_init()
{ {
m_window = new GraphicBuffer(m_pTexture->realWidth, m_pTexture->realHeight,
PIXEL_FORMAT_RGBA_8888, GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE);
EGLint eglImgAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE };
m_image = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)m_window->getNativeBuffer(), eglImgAttrs);
m_glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES"); m_glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
m_window = new GraphicBuffer();
} }
void ColorBufferToRDRAMAndroid::_destroy() void ColorBufferToRDRAMAndroid::_destroy()
{ {
eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), m_image); }
void ColorBufferToRDRAMAndroid::_initBuffers(void)
{
m_window->reallocate(m_pTexture->realWidth, m_pTexture->realHeight,
PIXEL_FORMAT_RGBA_8888, GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE);
EGLint eglImgAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE };
m_image = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT,
EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)m_window->getNativeBuffer(), eglImgAttrs);
}
void ColorBufferToRDRAMAndroid::_destroyBuffers(void)
{
if(m_image != 0)
{
eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), m_image);
m_image = 0;
}
} }
GLubyte* ColorBufferToRDRAMAndroid::_getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) GLubyte* ColorBufferToRDRAMAndroid::_getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync)

View File

@ -13,8 +13,10 @@ private:
void _destroy() override; void _destroy() override;
GLubyte* _getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) override; GLubyte* _getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) override;
void _cleanUpPixels(GLubyte* pixelData) override; void _cleanUpPixels(GLubyte* pixelData) override;
void _initBuffers(void) override;
GLuint m_PBO[3]; void _destroyBuffers(void) override;
static const int _numPBO = 3;
GLuint m_PBO[_numPBO];
u32 m_curIndex; u32 m_curIndex;
}; };
@ -28,25 +30,42 @@ ColorBufferToRDRAMDesktop::ColorBufferToRDRAMDesktop()
: ColorBufferToRDRAM() : ColorBufferToRDRAM()
, m_curIndex(-1) , m_curIndex(-1)
{ {
m_PBO[0] = m_PBO[1] = m_PBO[2] = 0; for(int index = 0; index < _numPBO; ++index)
{
m_PBO[index] = 0;
}
} }
void ColorBufferToRDRAMDesktop::_init() void ColorBufferToRDRAMDesktop::_init()
{ {
// Generate and initialize Pixel Buffer Objects // Generate Pixel Buffer Objects
glGenBuffers(3, m_PBO); glGenBuffers(_numPBO, 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);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
m_curIndex = 0; m_curIndex = 0;
} }
void ColorBufferToRDRAMDesktop::_destroy() void ColorBufferToRDRAMDesktop::_destroy()
{ {
glDeleteBuffers(3, m_PBO); glDeleteBuffers(_numPBO, m_PBO);
m_PBO[0] = m_PBO[1] = m_PBO[2] = 0;
for(int index = 0; index < _numPBO; ++index)
{
m_PBO[index] = 0;
}
}
void ColorBufferToRDRAMDesktop::_initBuffers(void)
{
// Initialize Pixel Buffer Objects
for (u32 i = 0; i < _numPBO; ++i) {
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[i]);
glBufferData(GL_PIXEL_PACK_BUFFER, m_pTexture->textureBytes, NULL, GL_DYNAMIC_READ);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
void ColorBufferToRDRAMDesktop::_destroyBuffers(void)
{
} }
GLubyte* ColorBufferToRDRAMDesktop::_getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) GLubyte* ColorBufferToRDRAMDesktop::_getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync)
@ -68,22 +87,30 @@ GLubyte* ColorBufferToRDRAMDesktop::_getPixels(GLint _x0, GLint _y0, GLsizei _wi
m_curIndex ^= 1; m_curIndex ^= 1;
const u32 nextIndex = m_curIndex ^ 1; const u32 nextIndex = m_curIndex ^ 1;
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[m_curIndex]); glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[m_curIndex]);
glReadPixels(_x0, _y0, _width, _height, colorFormat, colorType, 0); glReadPixels(_x0, _y0, m_pTexture->realWidth, _height, colorFormat, colorType, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[nextIndex]); glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[nextIndex]);
} else { } else {
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[2]); glBindBuffer(GL_PIXEL_PACK_BUFFER, m_PBO[2]);
glReadPixels(_x0, _y0, _width, _height, colorFormat, colorType, 0); glReadPixels(_x0, _y0, m_pTexture->realWidth, _height, colorFormat, colorType, 0);
} }
GLubyte* pixelData = (GLubyte*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, _width * _height * colorFormatBytes, GL_MAP_READ_BIT); GLubyte* pixelData = (GLubyte*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, m_pTexture->realWidth * _height * colorFormatBytes, GL_MAP_READ_BIT);
if (pixelData == NULL) if (pixelData == NULL)
return NULL; return NULL;
return pixelData; int widthBytes = _width*colorFormatBytes;
int strideBytes = m_pTexture->realWidth * colorFormatBytes;
GLubyte* pixelDataAlloc = (GLubyte*)malloc(_width * _height * colorFormatBytes);
for (unsigned int lnIndex = 0; lnIndex < _height; ++lnIndex) {
memcpy(pixelDataAlloc + lnIndex*widthBytes, pixelData + (lnIndex*strideBytes), widthBytes);
}
return pixelDataAlloc;
} }
void ColorBufferToRDRAMDesktop::_cleanUpPixels(GLubyte* pixelData) void ColorBufferToRDRAMDesktop::_cleanUpPixels(GLubyte* pixelData)
{ {
glUnmapBuffer(GL_PIXEL_PACK_BUFFER); glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
free(pixelData);
} }