1
0
mirror of https://github.com/blawar/GLideN64.git synced 2024-07-04 10:03:36 +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 <N64.h>
#include <VI.h>
#include <Log.h>
ColorBufferToRDRAM::ColorBufferToRDRAM()
: m_FBO(0)
@ -16,7 +17,12 @@ ColorBufferToRDRAM::ColorBufferToRDRAM()
, m_pCurFrameBuffer(nullptr)
, m_frameCount(-1)
, m_startAddress(-1)
, m_lastVIWidth(-1)
, m_lastVIHeight(-1)
{
m_allowedRealWidths[0] = 320;
m_allowedRealWidths[1] = 480;
m_allowedRealWidths[2] = 640;
}
ColorBufferToRDRAM::~ColorBufferToRDRAM()
@ -30,6 +36,22 @@ void ColorBufferToRDRAM::init()
// generate a framebuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
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);
m_pTexture = textureCache().addFrameBufferTexture();
@ -41,8 +63,10 @@ void ColorBufferToRDRAM::init()
m_pTexture->maskT = 0;
m_pTexture->mirrorS = 0;
m_pTexture->mirrorT = 0;
m_pTexture->realWidth = 640;
m_pTexture->realHeight = 580;
//The actual VI width is not used for texture width because most texture widths
//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;
textureCache().addFrameBufferTextureSize(m_pTexture->textureBytes);
glBindTexture(GL_TEXTURE_2D, m_pTexture->glName);
@ -56,20 +80,16 @@ void ColorBufferToRDRAM::init()
assert(checkFBO());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// _init(m_pTexture->realWidth, m_pTexture->realHeight, m_pTexture->textureBytes);
_init();
_initBuffers();
}
void ColorBufferToRDRAM::destroy() {
_destroy();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
if (m_FBO != 0) {
glDeleteFramebuffers(1, &m_FBO);
m_FBO = 0;
}
if (m_pTexture != NULL) {
void ColorBufferToRDRAM::_destroyFBTexure(void)
{
_destroyBuffers();
if (m_pTexture != nullptr) {
textureCache().removeFrameBufferTexture(m_pTexture);
m_pTexture = NULL;
m_pTexture = nullptr;
}
}
@ -97,6 +117,16 @@ bool ColorBufferToRDRAM::_prepareCopy(u32 _startAddress)
if (height == 0)
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;
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;
}
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)
{
if (!_prepareCopy(_address))

View File

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

View File

@ -24,6 +24,8 @@ private:
void _destroy() override;
GLubyte* _getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) override;
void _cleanUpPixels(GLubyte* pixelData) override;
void _initBuffers(void) override;
void _destroyBuffers(void) override;
GraphicBuffer* m_window;
EGLImageKHR m_image;
@ -37,25 +39,39 @@ ColorBufferToRDRAM & ColorBufferToRDRAM::get()
}
ColorBufferToRDRAMAndroid::ColorBufferToRDRAMAndroid()
: ColorBufferToRDRAM()
: ColorBufferToRDRAM(),
m_window(nullptr),
m_image(0)
{
}
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_window = new GraphicBuffer();
}
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)

View File

@ -13,8 +13,10 @@ private:
void _destroy() override;
GLubyte* _getPixels(GLint _x0, GLint _y0, GLsizei _width, GLsizei _height, u32 _size, bool _sync) override;
void _cleanUpPixels(GLubyte* pixelData) override;
GLuint m_PBO[3];
void _initBuffers(void) override;
void _destroyBuffers(void) override;
static const int _numPBO = 3;
GLuint m_PBO[_numPBO];
u32 m_curIndex;
};
@ -28,25 +30,42 @@ ColorBufferToRDRAMDesktop::ColorBufferToRDRAMDesktop()
: ColorBufferToRDRAM()
, 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()
{
// Generate and initialize Pixel Buffer Objects
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);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
// Generate Pixel Buffer Objects
glGenBuffers(_numPBO, m_PBO);
m_curIndex = 0;
}
void ColorBufferToRDRAMDesktop::_destroy()
{
glDeleteBuffers(3, m_PBO);
m_PBO[0] = m_PBO[1] = m_PBO[2] = 0;
glDeleteBuffers(_numPBO, m_PBO);
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)
@ -68,22 +87,30 @@ GLubyte* ColorBufferToRDRAMDesktop::_getPixels(GLint _x0, GLint _y0, GLsizei _wi
m_curIndex ^= 1;
const u32 nextIndex = m_curIndex ^ 1;
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]);
} else {
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)
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)
{
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
free(pixelData);
}