opengles emulator: replace the readback at end of frame with blit

That replaces the readback to host we do at the end of each frame
with two blits on the GPU, one to copy the pixels into a texture
and another to render the texture to another in order to flip
the image.

Change-Id: I7e0e10493d38944d0b613e245023f34236d3dfc4
This commit is contained in:
Guy Zadickario
2011-08-16 10:52:19 +03:00
parent e16a448df0
commit 8c962dce6c
4 changed files with 145 additions and 2 deletions

View File

@@ -72,8 +72,24 @@ ColorBuffer *ColorBuffer::create(int p_width, int p_height,
s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
s_gl.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
//
// create another texture for that colorbuffer for blit
//
s_gl.glGenTextures(1, &cb->m_blitTex);
s_gl.glBindTexture(GL_TEXTURE_2D, cb->m_blitTex);
s_gl.glTexImage2D(GL_TEXTURE_2D, 0, texInternalFormat,
p_width, p_height, 0,
texInternalFormat,
GL_UNSIGNED_BYTE, NULL);
s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
s_gl.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
cb->m_width = p_width;
cb->m_height = p_height;
cb->m_internalFormat = texInternalFormat;
if (fb->getCaps().has_eglimage_texture_2d) {
cb->m_eglImage = s_egl.eglCreateImageKHR(fb->getDisplay(),
@@ -81,6 +97,12 @@ ColorBuffer *ColorBuffer::create(int p_width, int p_height,
EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)cb->m_tex,
NULL);
cb->m_blitEGLImage = s_egl.eglCreateImageKHR(fb->getDisplay(),
fb->getContext(),
EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)cb->m_blitTex,
NULL);
}
fb->unbind_locked();
@@ -90,7 +112,8 @@ ColorBuffer *ColorBuffer::create(int p_width, int p_height,
ColorBuffer::ColorBuffer() :
m_tex(0),
m_eglImage(NULL),
m_fbo(0)
m_fbo(0),
m_internalFormat(0)
{
}
@@ -176,6 +199,90 @@ bool ColorBuffer::blitFromPbuffer(EGLSurface p_pbufSurface)
return true;
}
bool ColorBuffer::blitFromCurrentReadBuffer()
{
RenderThreadInfo *tInfo = getRenderThreadInfo();
if (!tInfo->currContext.Ptr()) {
// no Current context
return false;
}
//
// Create a temporary texture inside the current context
// from the blit_texture EGLImage and copy the pixels
// from the current read buffer to that texture
//
GLuint tmpTex;
GLint currTexBind;
if (tInfo->currContext->isGL2()) {
s_gl2.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
s_gl2.glGenTextures(1,&tmpTex);
s_gl2.glBindTexture(GL_TEXTURE_2D, tmpTex);
s_gl2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
s_gl2.glCopyTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat,
0, 0, m_width, m_height, 0);
}
else {
s_gl.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
s_gl.glGenTextures(1,&tmpTex);
s_gl.glBindTexture(GL_TEXTURE_2D, tmpTex);
s_gl.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
s_gl.glCopyTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat,
0, 0, m_width, m_height, 0);
}
//
// Now bind the frame buffer context and blit from
// m_blitTex into m_tex
//
FrameBuffer *fb = FrameBuffer::getFB();
if (fb->bind_locked()) {
//
// bind FBO object which has this colorbuffer as render target
//
if (bind_fbo()) {
//
// save current viewport and match it to the current
// colorbuffer size
//
GLint vport[4];
s_gl.glGetIntegerv(GL_VIEWPORT, vport);
s_gl.glViewport(0, 0, m_width, m_height);
// render m_blitTex
s_gl.glBindTexture(GL_TEXTURE_2D, m_blitTex);
drawTexQuad(); // this will render the texture flipped
// unbind the fbo
s_gl.glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
// restrore previous viewport
s_gl.glViewport(vport[0], vport[1], vport[2], vport[3]);
}
// unbind from the FrameBuffer context
fb->unbind_locked();
}
//
// delete the temporary texture and restore the texture binding
// inside the current context
//
if (tInfo->currContext->isGL2()) {
s_gl2.glDeleteTextures(1, &tmpTex);
s_gl2.glBindTexture(GL_TEXTURE_2D, currTexBind);
}
else {
s_gl.glDeleteTextures(1, &tmpTex);
s_gl.glBindTexture(GL_TEXTURE_2D, currTexBind);
}
return true;
}
bool ColorBuffer::bindToTexture()
{
if (m_eglImage) {

View File

@@ -38,6 +38,7 @@ public:
bool post();
bool bindToTexture();
bool bindToRenderbuffer();
bool blitFromCurrentReadBuffer();
private:
ColorBuffer();
@@ -46,10 +47,13 @@ private:
private:
GLuint m_tex;
GLuint m_blitTex;
EGLImageKHR m_eglImage;
EGLImageKHR m_blitEGLImage;
GLuint m_width;
GLuint m_height;
GLuint m_fbo;
GLenum m_internalFormat;
};
typedef SmartPtr<ColorBuffer> ColorBufferPtr;

View File

@@ -115,7 +115,8 @@ void WindowSurface::flushColorBuffer()
}
if (!copied) {
copyToColorBuffer();
//copyToColorBuffer();
blitToColorBuffer();
}
}
else {
@@ -257,6 +258,36 @@ void WindowSurface::copyToColorBuffer()
}
void WindowSurface::blitToColorBuffer()
{
if (!m_width && !m_height) return;
if (m_attachedColorBuffer->getWidth() != m_width ||
m_attachedColorBuffer->getHeight() != m_height) {
// XXX: should never happen - how this needs to be handled?
return;
}
//
// Make the surface current
//
EGLContext prevContext = s_egl.eglGetCurrentContext();
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
FrameBuffer *fb = FrameBuffer::getFB();
if (!s_egl.eglMakeCurrent(fb->getDisplay(), m_eglSurface,
m_eglSurface, m_drawContext->getEGLContext())) {
return;
}
m_attachedColorBuffer->blitFromCurrentReadBuffer();
// restore current context/surface
s_egl.eglMakeCurrent(fb->getDisplay(), prevDrawSurf,
prevReadSurf, prevContext);
}
bool WindowSurface::resizePbuffer(unsigned int p_width, unsigned int p_height)
{
if (m_eglSurface &&

View File

@@ -45,6 +45,7 @@ private:
WindowSurface();
void copyToColorBuffer(); // copy pbuffer content with readback+download
void blitToColorBuffer(); // copy pbuffer content with texload and blit
bool resizePbuffer(unsigned int p_width, unsigned int p_height);
private: