diff --git a/src/anbox/graphics/emugl/ColorBuffer.cpp b/src/anbox/graphics/emugl/ColorBuffer.cpp index 7d67ba3c0ef4027ce2994648534fbdda9d23b770..75c021d9aa7b57c77ace003283d480deb5677ff3 100644 --- a/src/anbox/graphics/emugl/ColorBuffer.cpp +++ b/src/anbox/graphics/emugl/ColorBuffer.cpp @@ -31,7 +31,7 @@ namespace { // implemented as unsigned integers. These convenience template functions // help casting between them safely without generating compiler warnings. inline void* SafePointerFromUInt(unsigned int handle) { - return reinterpret_cast(static_cast(handle)); + return reinterpret_cast(static_cast(handle)); } // Lazily create and bind a framebuffer object to the current host context. @@ -40,25 +40,25 @@ inline void* SafePointerFromUInt(unsigned int handle) { // on creation only. I.e. all rendering operations will target it. // returns true in case of success, false on failure. bool bindFbo(GLuint* fbo, GLuint tex) { - if (*fbo) { - // fbo already exist - just bind + if (*fbo) { + // fbo already exist - just bind + s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, *fbo); + return true; + } + + s_gles2.glGenFramebuffers(1, fbo); s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, *fbo); + s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_OES, + GL_TEXTURE_2D, tex, 0); + GLenum status = s_gles2.glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE_OES) { + ERROR("FBO not complete: %#x", status); + s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0); + s_gles2.glDeleteFramebuffers(1, fbo); + *fbo = 0; + return false; + } return true; - } - - s_gles2.glGenFramebuffers(1, fbo); - s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, *fbo); - s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_OES, - GL_TEXTURE_2D, tex, 0); - GLenum status = s_gles2.glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE_OES) { - ERROR("FBO not complete: %#x", status); - s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0); - s_gles2.glDeleteFramebuffers(1, fbo); - *fbo = 0; - return false; - } - return true; } void unbindFbo() { s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -75,26 +75,26 @@ void unbindFbo() { s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0); } // } // automatically calls m_helper->teardownContext(); // class ScopedHelperContext { - public: - ScopedHelperContext(ColorBuffer::Helper* helper) : mHelper(helper) { - if (!helper->setupContext()) { - mHelper = NULL; +public: + ScopedHelperContext(ColorBuffer::Helper* helper) : mHelper(helper) { + if (!helper->setupContext()) { + mHelper = NULL; + } } - } - bool isOk() const { return mHelper != NULL; } + bool isOk() const { return mHelper != NULL; } - ~ScopedHelperContext() { release(); } + ~ScopedHelperContext() { release(); } - void release() { - if (mHelper) { - mHelper->teardownContext(); - mHelper = NULL; + void release() { + if (mHelper) { + mHelper->teardownContext(); + mHelper = NULL; + } } - } - private: - ColorBuffer::Helper* mHelper; +private: + ColorBuffer::Helper* mHelper; }; } // namespace @@ -103,83 +103,83 @@ class ScopedHelperContext { ColorBuffer* ColorBuffer::create(EGLDisplay p_display, int p_width, int p_height, GLenum p_internalFormat, bool has_eglimage_texture_2d, Helper* helper, HandleType hndl) { - GLenum texInternalFormat = 0; - - switch (p_internalFormat) { - case GL_RGB: - case GL_RGB565_OES: - texInternalFormat = GL_RGB; - break; - - case GL_RGBA: - case GL_RGB5_A1_OES: - case GL_RGBA4_OES: - texInternalFormat = GL_RGBA; - break; - - default: - return NULL; - break; - } - - ScopedHelperContext context(helper); - if (!context.isOk()) { - return NULL; - } - - ColorBuffer* cb = new ColorBuffer(p_display, helper, hndl); - if (!cb) { - return NULL; - } - - s_gles2.glGenTextures(1, &cb->m_tex); - s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_tex); - - int nComp = (texInternalFormat == GL_RGB ? 3 : 4); - - char* zBuff = static_cast(::calloc(nComp * p_width * p_height, 1)); - s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, texInternalFormat, p_width, p_height, - 0, texInternalFormat, GL_UNSIGNED_BYTE, zBuff); - ::free(zBuff); - - s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // - // create another texture for that colorbuffer for blit - // - s_gles2.glGenTextures(1, &cb->m_blitTex); - s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_blitTex); - s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, texInternalFormat, p_width, p_height, - 0, texInternalFormat, GL_UNSIGNED_BYTE, NULL); - - s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - cb->m_width = p_width; - cb->m_height = p_height; - cb->m_internalFormat = texInternalFormat; - - if (has_eglimage_texture_2d) { - cb->m_eglImage = s_egl.eglCreateImageKHR( - p_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR, - reinterpret_cast(SafePointerFromUInt(cb->m_tex)), NULL); - - cb->m_blitEGLImage = s_egl.eglCreateImageKHR( - p_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR, - reinterpret_cast(SafePointerFromUInt(cb->m_blitTex)), NULL); - } - - cb->m_resizer = new TextureResize(p_width, p_height); - if (!(cb->m_resizer)) { - return NULL; - } - - return cb; + GLenum texInternalFormat = 0; + + switch (p_internalFormat) { + case GL_RGB: + case GL_RGB565_OES: + texInternalFormat = GL_RGB; + break; + + case GL_RGBA: + case GL_RGB5_A1_OES: + case GL_RGBA4_OES: + texInternalFormat = GL_RGBA; + break; + + default: + return NULL; + break; + } + + ScopedHelperContext context(helper); + if (!context.isOk()) { + return NULL; + } + + ColorBuffer* cb = new ColorBuffer(p_display, helper, hndl); + if (!cb) { + return NULL; + } + + s_gles2.glGenTextures(1, &cb->m_tex); + s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_tex); + + int nComp = (texInternalFormat == GL_RGB ? 3 : 4); + + char* zBuff = static_cast(::calloc(nComp * p_width * p_height, 1)); + s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, texInternalFormat, p_width, p_height, + 0, texInternalFormat, GL_UNSIGNED_BYTE, zBuff); + ::free(zBuff); + + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // + // create another texture for that colorbuffer for blit + // + s_gles2.glGenTextures(1, &cb->m_blitTex); + s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_blitTex); + s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, texInternalFormat, p_width, p_height, + 0, texInternalFormat, GL_UNSIGNED_BYTE, NULL); + + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + cb->m_width = p_width; + cb->m_height = p_height; + cb->m_internalFormat = texInternalFormat; + + if (has_eglimage_texture_2d) { + cb->m_eglImage = s_egl.eglCreateImageKHR( + p_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR, + reinterpret_cast(SafePointerFromUInt(cb->m_tex)), NULL); + + cb->m_blitEGLImage = s_egl.eglCreateImageKHR( + p_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR, + reinterpret_cast(SafePointerFromUInt(cb->m_blitTex)), NULL); + } + + cb->m_resizer = new TextureResize(p_width, p_height); + if (!(cb->m_resizer)) { + return NULL; + } + + return cb; } ColorBuffer::ColorBuffer(EGLDisplay display, Helper* helper, HandleType hndl) @@ -194,23 +194,23 @@ ColorBuffer::ColorBuffer(EGLDisplay display, Helper* helper, HandleType hndl) mHndl(hndl) {} ColorBuffer::~ColorBuffer() { - ScopedHelperContext context(m_helper); + ScopedHelperContext context(m_helper); - if (m_blitEGLImage) { - s_egl.eglDestroyImageKHR(m_display, m_blitEGLImage); - } - if (m_eglImage) { - s_egl.eglDestroyImageKHR(m_display, m_eglImage); - } + if (m_blitEGLImage) { + s_egl.eglDestroyImageKHR(m_display, m_blitEGLImage); + } + if (m_eglImage) { + s_egl.eglDestroyImageKHR(m_display, m_eglImage); + } - if (m_fbo) { - s_gles2.glDeleteFramebuffers(1, &m_fbo); - } + if (m_fbo) { + s_gles2.glDeleteFramebuffers(1, &m_fbo); + } - GLuint tex[2] = {m_tex, m_blitTex}; - s_gles2.glDeleteTextures(2, tex); + GLuint tex[2] = {m_tex, m_blitTex}; + s_gles2.glDeleteTextures(2, tex); - delete m_resizer; + delete m_resizer; } HandleType ColorBuffer::getHndl() const { @@ -219,144 +219,144 @@ HandleType ColorBuffer::getHndl() const { void ColorBuffer::readPixels(int x, int y, int width, int height, GLenum p_format, GLenum p_type, void* pixels) { - ScopedHelperContext context(m_helper); - if (!context.isOk()) { - return; - } + ScopedHelperContext context(m_helper); + if (!context.isOk()) { + return; + } - if (bindFbo(&m_fbo, m_tex)) { - s_gles2.glReadPixels(x, y, width, height, p_format, p_type, pixels); - unbindFbo(); - } + if (bindFbo(&m_fbo, m_tex)) { + s_gles2.glReadPixels(x, y, width, height, p_format, p_type, pixels); + unbindFbo(); + } } void ColorBuffer::subUpdate(int x, int y, int width, int height, GLenum p_format, GLenum p_type, void* pixels) { - ScopedHelperContext context(m_helper); - if (!context.isOk()) { - return; - } - - s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex); - s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - s_gles2.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, p_format, - p_type, pixels); + ScopedHelperContext context(m_helper); + if (!context.isOk()) { + return; + } + + s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex); + s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + s_gles2.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, p_format, + p_type, pixels); } bool ColorBuffer::blitFromCurrentReadBuffer() { - RenderThreadInfo* tInfo = RenderThreadInfo::get(); - if (!tInfo) { - return false; - } - if (!tInfo->currContext) { - // no Current context - return false; - } - - // Copy the content of the current read surface into m_blitEGLImage. - // This is done by creating a temporary texture, bind it to the EGLImage - // then call glCopyTexSubImage2D(). - GLuint tmpTex; - GLint currTexBind; - if (tInfo->currContext->isGL2()) { - s_gles2.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind); - s_gles2.glGenTextures(1, &tmpTex); - s_gles2.glBindTexture(GL_TEXTURE_2D, tmpTex); - s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage); - s_gles2.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, - m_height); - s_gles2.glDeleteTextures(1, &tmpTex); - s_gles2.glBindTexture(GL_TEXTURE_2D, currTexBind); - } else { - s_gles1.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind); - s_gles1.glGenTextures(1, &tmpTex); - s_gles1.glBindTexture(GL_TEXTURE_2D, tmpTex); - s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage); - s_gles1.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, - m_height); - s_gles1.glDeleteTextures(1, &tmpTex); - s_gles1.glBindTexture(GL_TEXTURE_2D, currTexBind); - } - - ScopedHelperContext context(m_helper); - if (!context.isOk()) { - return false; - } - - if (!bindFbo(&m_fbo, m_tex)) { - return false; - } - - // Save current viewport and match it to the current colorbuffer size. - GLint vport[4] = { - 0, - }; - s_gles2.glGetIntegerv(GL_VIEWPORT, vport); - s_gles2.glViewport(0, 0, m_width, m_height); - - // render m_blitTex - m_helper->getTextureDraw()->draw(m_blitTex); - - // Restore previous viewport. - s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]); - unbindFbo(); - - return true; + RenderThreadInfo* tInfo = RenderThreadInfo::get(); + if (!tInfo) { + return false; + } + if (!tInfo->currContext) { + // no Current context + return false; + } + + // Copy the content of the current read surface into m_blitEGLImage. + // This is done by creating a temporary texture, bind it to the EGLImage + // then call glCopyTexSubImage2D(). + GLuint tmpTex; + GLint currTexBind; + if (tInfo->currContext->isGL2()) { + s_gles2.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind); + s_gles2.glGenTextures(1, &tmpTex); + s_gles2.glBindTexture(GL_TEXTURE_2D, tmpTex); + s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage); + s_gles2.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, + m_height); + s_gles2.glDeleteTextures(1, &tmpTex); + s_gles2.glBindTexture(GL_TEXTURE_2D, currTexBind); + } else { + s_gles1.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind); + s_gles1.glGenTextures(1, &tmpTex); + s_gles1.glBindTexture(GL_TEXTURE_2D, tmpTex); + s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage); + s_gles1.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width, + m_height); + s_gles1.glDeleteTextures(1, &tmpTex); + s_gles1.glBindTexture(GL_TEXTURE_2D, currTexBind); + } + + ScopedHelperContext context(m_helper); + if (!context.isOk()) { + return false; + } + + if (!bindFbo(&m_fbo, m_tex)) { + return false; + } + + // Save current viewport and match it to the current colorbuffer size. + GLint vport[4] = { + 0, + }; + s_gles2.glGetIntegerv(GL_VIEWPORT, vport); + s_gles2.glViewport(0, 0, m_width, m_height); + + // render m_blitTex + m_helper->getTextureDraw()->draw(m_blitTex); + + // Restore previous viewport. + s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]); + unbindFbo(); + + return true; } bool ColorBuffer::bindToTexture() { - if (!m_eglImage) { - return false; - } - RenderThreadInfo* tInfo = RenderThreadInfo::get(); - if (!tInfo) { - return false; - } - if (!tInfo->currContext) { - return false; - } - if (tInfo->currContext->isGL2()) { - s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage); - } else { - s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage); - } - return true; + if (!m_eglImage) { + return false; + } + RenderThreadInfo* tInfo = RenderThreadInfo::get(); + if (!tInfo) { + return false; + } + if (!tInfo->currContext) { + return false; + } + if (tInfo->currContext->isGL2()) { + s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage); + } else { + s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage); + } + return true; } bool ColorBuffer::bindToRenderbuffer() { - if (!m_eglImage) { - return false; - } - RenderThreadInfo* tInfo = RenderThreadInfo::get(); - if (!tInfo) { - return false; - } - if (!tInfo->currContext) { - return false; - } - if (tInfo->currContext->isGL2()) { - s_gles2.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, - m_eglImage); - } else { - s_gles1.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, - m_eglImage); - } - return true; + if (!m_eglImage) { + return false; + } + RenderThreadInfo* tInfo = RenderThreadInfo::get(); + if (!tInfo) { + return false; + } + if (!tInfo->currContext) { + return false; + } + if (tInfo->currContext->isGL2()) { + s_gles2.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, + m_eglImage); + } else { + s_gles1.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, + m_eglImage); + } + return true; } void ColorBuffer::readback(unsigned char* img) { - ScopedHelperContext context(m_helper); - if (!context.isOk()) { - return; - } - if (bindFbo(&m_fbo, m_tex)) { - s_gles2.glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, - img); - unbindFbo(); - } + ScopedHelperContext context(m_helper); + if (!context.isOk()) { + return; + } + if (bindFbo(&m_fbo, m_tex)) { + s_gles2.glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, + img); + unbindFbo(); + } } void ColorBuffer::bind() { - const auto id = m_resizer->update(m_tex); - s_gles2.glBindTexture(GL_TEXTURE_2D, id); + const auto id = m_resizer->update(m_tex); + s_gles2.glBindTexture(GL_TEXTURE_2D, id); }