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: