X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fsrc%2Fanbox%2Fgraphics%2Femugl%2FColorBuffer.cpp;fp=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fsrc%2Fanbox%2Fgraphics%2Femugl%2FColorBuffer.cpp;h=f336c83f23e772470b0a4843862d389778a803c2;hb=e26c1ec581be598521517829adba8c8dd23a768f;hp=0000000000000000000000000000000000000000;hpb=6699c1aea74eeb0eb400e6299079f0c7576f716f;p=iec.git diff --git a/src/type3_AndroidCloud/anbox-master/src/anbox/graphics/emugl/ColorBuffer.cpp b/src/type3_AndroidCloud/anbox-master/src/anbox/graphics/emugl/ColorBuffer.cpp new file mode 100644 index 0000000..f336c83 --- /dev/null +++ b/src/type3_AndroidCloud/anbox-master/src/anbox/graphics/emugl/ColorBuffer.cpp @@ -0,0 +1,342 @@ +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "anbox/graphics/emugl/ColorBuffer.h" +#include "anbox/graphics/emugl/DispatchTables.h" +#include "anbox/graphics/emugl/RenderThreadInfo.h" +#include "anbox/graphics/emugl/TextureDraw.h" +#include "anbox/graphics/emugl/TextureResize.h" +#include "anbox/logger.h" + +#include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h" + +#include + +namespace { + +// defines many types as 'void*' while they're really +// 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)); +} + +// Lazily create and bind a framebuffer object to the current host context. +// |fbo| is the address of the framebuffer object name. +// |tex| is the name of a texture that is attached to the framebuffer object +// 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 + 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; +} + +void unbindFbo() { s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0); } + +// Helper class to use a ColorBuffer::Helper context. +// Usage is pretty simple: +// +// { +// ScopedHelperContext context(m_helper); +// if (!context.isOk()) { +// return false; // something bad happened. +// } +// .... do something .... +// } // automatically calls m_helper->teardownContext(); +// +class ScopedHelperContext { + public: + ScopedHelperContext(ColorBuffer::Helper* helper) : mHelper(helper) { + if (!helper->setupContext()) { + mHelper = NULL; + } + } + + bool isOk() const { return mHelper != NULL; } + + ~ScopedHelperContext() { release(); } + + void release() { + if (mHelper) { + mHelper->teardownContext(); + mHelper = NULL; + } + } + + private: + ColorBuffer::Helper* mHelper; +}; + +} // namespace + +// static +ColorBuffer* ColorBuffer::create(EGLDisplay p_display, int p_width, + int p_height, GLenum p_internalFormat, + bool has_eglimage_texture_2d, Helper* helper) { + 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); + + 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); + + return cb; +} + +ColorBuffer::ColorBuffer(EGLDisplay display, Helper* helper) + : m_tex(0), + m_blitTex(0), + m_eglImage(NULL), + m_blitEGLImage(NULL), + m_fbo(0), + m_internalFormat(0), + m_display(display), + m_helper(helper) {} + +ColorBuffer::~ColorBuffer() { + 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_fbo) { + s_gles2.glDeleteFramebuffers(1, &m_fbo); + } + + GLuint tex[2] = {m_tex, m_blitTex}; + s_gles2.glDeleteTextures(2, tex); + + delete m_resizer; +} + +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; + } + + 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); +} + +bool ColorBuffer::blitFromCurrentReadBuffer() { + RenderThreadInfo* tInfo = RenderThreadInfo::get(); + 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->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->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(); + } +} + +void ColorBuffer::bind() { + const auto id = m_resizer->update(m_tex); + s_gles2.glBindTexture(GL_TEXTURE_2D, id); +}