From 8c962dce6c95417d47a1e4cd9d41ee6a9327ba95 Mon Sep 17 00:00:00 2001 From: Guy Zadickario Date: Tue, 16 Aug 2011 10:52:19 +0300 Subject: [PATCH] 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 --- .../host/libs/libOpenglRender/ColorBuffer.cpp | 109 +++++++++++++++++- .../host/libs/libOpenglRender/ColorBuffer.h | 4 + .../libs/libOpenglRender/WindowSurface.cpp | 33 +++++- .../host/libs/libOpenglRender/WindowSurface.h | 1 + 4 files changed, 145 insertions(+), 2 deletions(-) diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/ColorBuffer.cpp b/tools/emulator/opengl/host/libs/libOpenglRender/ColorBuffer.cpp index b0a1ba2b3..c39dac31c 100644 --- a/tools/emulator/opengl/host/libs/libOpenglRender/ColorBuffer.cpp +++ b/tools/emulator/opengl/host/libs/libOpenglRender/ColorBuffer.cpp @@ -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) { diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/ColorBuffer.h b/tools/emulator/opengl/host/libs/libOpenglRender/ColorBuffer.h index 4bc495a80..5e01dccc5 100644 --- a/tools/emulator/opengl/host/libs/libOpenglRender/ColorBuffer.h +++ b/tools/emulator/opengl/host/libs/libOpenglRender/ColorBuffer.h @@ -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 ColorBufferPtr; diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.cpp b/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.cpp index 36fb70477..14f38be33 100644 --- a/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.cpp +++ b/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.cpp @@ -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 && diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.h b/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.h index de9bc7bcd..6c089540e 100644 --- a/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.h +++ b/tools/emulator/opengl/host/libs/libOpenglRender/WindowSurface.h @@ -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: