/* * 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/RenderControl.h" #include "anbox/graphics/emugl/DispatchTables.h" #include "anbox/graphics/emugl/DisplayManager.h" #include "anbox/graphics/emugl/RenderThreadInfo.h" #include "anbox/graphics/emugl/Renderer.h" #include "anbox/graphics/emugl/RendererConfig.h" #include "anbox/graphics/layer_composer.h" #include "anbox/logger.h" #include "external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h" #include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h" #include #include #include static const GLint rendererVersion = 1; static std::shared_ptr composer; static std::shared_ptr renderer; void registerLayerComposer( const std::shared_ptr &c) { composer = c; } void registerRenderer(const std::shared_ptr &r) { renderer = r; } static GLint rcGetRendererVersion() { return rendererVersion; } static EGLint rcGetEGLVersion(EGLint *major, EGLint *minor) { if (!renderer) return EGL_FALSE; *major = static_cast(renderer->getCaps().eglMajor); *minor = static_cast(renderer->getCaps().eglMinor); return EGL_TRUE; } static std::string filter_extensions(const std::string& extensions, const std::vector& whitelist) { std::stringstream approved_extensions; auto extension_list = anbox::utils::string_split(extensions, ' '); for (const auto& ext : extension_list) { if (std::find(whitelist.begin(), whitelist.end(), ext) == whitelist.end()) continue; if (approved_extensions.tellp() > 0) approved_extensions << " "; approved_extensions << ext; } return approved_extensions.str(); } static EGLint rcQueryEGLString(EGLenum name, void* buffer, EGLint bufferSize) { if (!renderer) return 0; std::string result = s_egl.eglQueryString(renderer->getDisplay(), name); if (result.empty()) return 0; if (name == EGL_EXTENSIONS) { // We need to drop a few extensions from the list reported by the driver // as not all are well enough support by our EGL implementation. std::vector whitelisted_extensions = { "EGL_KHR_image_base", "EGL_KHR_gl_texture_2D_image", }; result = filter_extensions(result, whitelisted_extensions); } int len = result.length() + 1; if (!buffer || len > bufferSize) { return -len; } strcpy(static_cast(buffer), result.c_str()); return len; } static EGLint rcGetGLString(EGLenum name, void* buffer, EGLint bufferSize) { RenderThreadInfo* tInfo = RenderThreadInfo::get(); std::string result; if (tInfo && tInfo->currContext) { const char* str = nullptr; if (tInfo->currContext->isGL2()) str = reinterpret_cast(s_gles2.glGetString(name)); else str = reinterpret_cast(s_gles1.glGetString(name)); if (str) result += str; } // We're forcing version 2.0 no matter what the host provides as // our emulation layer isn't prepared for anything newer (yet). // This goes in parallel with filtering the extension set for // any unwanted extensions. If we don't force the right version // here certain parts of the system will assume API conditions // which aren't met. if (name == GL_VERSION) result = "OpenGL ES 2.0"; else if (name == GL_EXTENSIONS) { // We need to drop a few extensions from the list reported by the driver // as not all are well enough support by our GL implementation. std::vector whitelisted_extensions = { "GL_OES_EGL_image", "GL_OES_EGL_image_external", "GL_OES_depth24", "GL_OES_depth32", "GL_OES_element_index_uint", "GL_OES_texture_float", "GL_OES_texture_float_linear", "GL_OES_compressed_paletted_texture", "GL_OES_compressed_ETC1_RGB8_texture", "GL_OES_depth_texture", "GL_OES_texture_half_float", "GL_OES_texture_half_float_linear", "GL_OES_packed_depth_stencil", "GL_OES_vertex_half_float", "GL_OES_standard_derivatives", "GL_OES_texture_npot", "GL_OES_rgb8_rgba8", }; result = filter_extensions(result, whitelisted_extensions); } int nextBufferSize = result.size() + 1; if (!buffer || nextBufferSize > bufferSize) return -nextBufferSize; snprintf(static_cast(buffer), nextBufferSize, "%s", result.c_str()); return nextBufferSize; } static EGLint rcGetNumConfigs(uint32_t *p_numAttribs) { int numConfigs = 0, numAttribs = 0; renderer->getConfigs()->getPackInfo(&numConfigs, &numAttribs); if (p_numAttribs) { *p_numAttribs = static_cast(numAttribs); } return numConfigs; } static EGLint rcGetConfigs(uint32_t bufSize, GLuint *buffer) { GLuint bufferSize = static_cast(bufSize); return renderer->getConfigs()->packConfigs(bufferSize, buffer); } static EGLint rcChooseConfig(EGLint *attribs, uint32_t attribs_size, uint32_t *configs, uint32_t configs_size) { if (!renderer || attribs_size == 0) return 0; return renderer->getConfigs()->chooseConfig(attribs, reinterpret_cast(configs), static_cast(configs_size)); } static EGLint rcGetFBParam(EGLint param) { if (!renderer) return 0; EGLint ret = 0; switch (param) { case FB_WIDTH: ret = static_cast(anbox::graphics::emugl::DisplayInfo::get()->vertical_resolution()); break; case FB_HEIGHT: ret = static_cast(anbox::graphics::emugl::DisplayInfo::get()->horizontal_resolution()); break; case FB_XDPI: ret = 72; // XXX: should be implemented break; case FB_YDPI: ret = 72; // XXX: should be implemented break; case FB_FPS: ret = 60; break; case FB_MIN_SWAP_INTERVAL: ret = 1; // XXX: should be implemented break; case FB_MAX_SWAP_INTERVAL: ret = 1; // XXX: should be implemented break; default: break; } return ret; } static uint32_t rcCreateContext(uint32_t config, uint32_t share, uint32_t glVersion) { if (!renderer) return 0; // To make it consistent with the guest, create GLES2 context when GL // version==2 or 3 HandleType ret = renderer->createRenderContext(config, share, glVersion == 2 || glVersion == 3); return ret; } static void rcDestroyContext(uint32_t context) { if (!renderer) return; renderer->DestroyRenderContext(context); } static uint32_t rcCreateWindowSurface(uint32_t config, uint32_t width, uint32_t height) { if (!renderer) return 0; return renderer->createWindowSurface(config, width, height); } static void rcDestroyWindowSurface(uint32_t windowSurface) { if (!renderer) return; renderer->DestroyWindowSurface(windowSurface); } static uint32_t rcCreateColorBuffer(uint32_t width, uint32_t height, GLenum internalFormat) { if (!renderer) return 0; return renderer->createColorBuffer(width, height, internalFormat); } static int rcOpenColorBuffer2(uint32_t colorbuffer) { if (!renderer) return -1; return renderer->openColorBuffer(colorbuffer); } // Deprecated, kept for compatibility with old system images only. // Use rcOpenColorBuffer2 instead. static void rcOpenColorBuffer(uint32_t colorbuffer) { (void)rcOpenColorBuffer2(colorbuffer); } static void rcCloseColorBuffer(uint32_t colorbuffer) { if (!renderer) return; renderer->closeColorBuffer(colorbuffer); } static int rcFlushWindowColorBuffer(uint32_t windowSurface) { if (!renderer) return -1; if (!renderer->flushWindowSurfaceColorBuffer(windowSurface)) return -1; return 0; } static void rcSetWindowColorBuffer(uint32_t windowSurface, uint32_t colorBuffer) { if (!renderer) return; renderer->setWindowSurfaceColorBuffer(windowSurface, colorBuffer); } static EGLint rcMakeCurrent(uint32_t context, uint32_t drawSurf, uint32_t readSurf) { if (!renderer) return EGL_FALSE; bool ret = renderer->bindContext(context, drawSurf, readSurf); return (ret ? EGL_TRUE : EGL_FALSE); } static void rcFBPost(uint32_t) { WARNING("Not implemented"); } static void rcFBSetSwapInterval(EGLint) { // XXX: TBD - should be implemented } static void rcBindTexture(uint32_t colorBuffer) { if (!renderer) return; renderer->bindColorBufferToTexture(colorBuffer); } static void rcBindRenderbuffer(uint32_t colorBuffer) { if (!renderer) return; renderer->bindColorBufferToRenderbuffer(colorBuffer); } static EGLint rcColorBufferCacheFlush(uint32_t, EGLint, int) { // XXX: TBD - should be implemented return 0; } static void rcReadColorBuffer(uint32_t colorBuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void *pixels) { if (!renderer) return; renderer->readColorBuffer(colorBuffer, x, y, width, height, format, type, pixels); } static int rcUpdateColorBuffer(uint32_t colorBuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void *pixels) { if (!renderer) return -1; renderer->updateColorBuffer(colorBuffer, x, y, width, height, format, type, pixels); return 0; } static uint32_t rcCreateClientImage(uint32_t context, EGLenum target, GLuint buffer) { if (!renderer) return 0; return renderer->createClientImage(context, target, buffer); } static int rcDestroyClientImage(uint32_t image) { if (!renderer) return 0; return renderer->destroyClientImage(image); } static void rcSelectChecksumCalculator(uint32_t protocol, uint32_t) { ChecksumCalculatorThreadInfo::setVersion(protocol); } int rcGetNumDisplays() { // For now we only support a single display but that single display // will contain more than one display so that we simply spawn up a big // virtual display which should match the real display arrangement // in most cases. return 1; } int rcGetDisplayWidth(uint32_t display_id) { (void)display_id; return static_cast(anbox::graphics::emugl::DisplayInfo::get()->vertical_resolution()); } int rcGetDisplayHeight(uint32_t display_id) { (void)display_id; return static_cast(anbox::graphics::emugl::DisplayInfo::get()->horizontal_resolution()); } int rcGetDisplayDpiX(uint32_t display_id) { (void)display_id; return 120; } int rcGetDisplayDpiY(uint32_t display_id) { (void)display_id; return 120; } int rcGetDisplayVsyncPeriod(uint32_t display_id) { (void)display_id; return 1; } static std::vector frame_layers; bool is_layer_blacklisted(const std::string &name) { static std::vector blacklist = { // The 'Sprite' layer is the mouse cursor Android uses as soon // as it has a pointer input device available. We don't want to // display this layer at all but don't have a good way of disabling // the cursor on the Android side yet. "Sprite", }; return std::find(blacklist.begin(), blacklist.end(), name) != blacklist.end(); } void rcPostLayer(const char *name, uint32_t color_buffer, float alpha, int32_t sourceCropLeft, int32_t sourceCropTop, int32_t sourceCropRight, int32_t sourceCropBottom, int32_t displayFrameLeft, int32_t displayFrameTop, int32_t displayFrameRight, int32_t displayFrameBottom) { Renderable r{ name, color_buffer, alpha, {displayFrameLeft, displayFrameTop, displayFrameRight, displayFrameBottom}, {sourceCropLeft, sourceCropTop, sourceCropRight, sourceCropBottom}}; frame_layers.push_back(r); } void rcPostAllLayersDone() { if (composer) composer->submit_layers(frame_layers); frame_layers.clear(); } void initRenderControlContext(renderControl_decoder_context_t *dec) { dec->rcGetRendererVersion = rcGetRendererVersion; dec->rcGetEGLVersion = rcGetEGLVersion; dec->rcQueryEGLString = rcQueryEGLString; dec->rcGetGLString = rcGetGLString; dec->rcGetNumConfigs = rcGetNumConfigs; dec->rcGetConfigs = rcGetConfigs; dec->rcChooseConfig = rcChooseConfig; dec->rcGetFBParam = rcGetFBParam; dec->rcCreateContext = rcCreateContext; dec->rcDestroyContext = rcDestroyContext; dec->rcCreateWindowSurface = rcCreateWindowSurface; dec->rcDestroyWindowSurface = rcDestroyWindowSurface; dec->rcCreateColorBuffer = rcCreateColorBuffer; dec->rcOpenColorBuffer = rcOpenColorBuffer; dec->rcCloseColorBuffer = rcCloseColorBuffer; dec->rcSetWindowColorBuffer = rcSetWindowColorBuffer; dec->rcFlushWindowColorBuffer = rcFlushWindowColorBuffer; dec->rcMakeCurrent = rcMakeCurrent; dec->rcFBPost = rcFBPost; dec->rcFBSetSwapInterval = rcFBSetSwapInterval; dec->rcBindTexture = rcBindTexture; dec->rcBindRenderbuffer = rcBindRenderbuffer; dec->rcColorBufferCacheFlush = rcColorBufferCacheFlush; dec->rcReadColorBuffer = rcReadColorBuffer; dec->rcUpdateColorBuffer = rcUpdateColorBuffer; dec->rcOpenColorBuffer2 = rcOpenColorBuffer2; dec->rcCreateClientImage = rcCreateClientImage; dec->rcDestroyClientImage = rcDestroyClientImage; dec->rcSelectChecksumCalculator = rcSelectChecksumCalculator; dec->rcGetNumDisplays = rcGetNumDisplays; dec->rcGetDisplayWidth = rcGetDisplayWidth; dec->rcGetDisplayHeight = rcGetDisplayHeight; dec->rcGetDisplayDpiX = rcGetDisplayDpiX; dec->rcGetDisplayDpiY = rcGetDisplayDpiY; dec->rcGetDisplayVsyncPeriod = rcGetDisplayVsyncPeriod; dec->rcPostLayer = rcPostLayer; dec->rcPostAllLayersDone = rcPostAllLayersDone; }