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:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user