Anbox源码分析(三)——Anbox渲染原理(源码分析)

Anbox源码分析(三)

上一篇,我们介绍了Anbox视频渲染的原理,这一篇,我们从源码入手,更深入的理解Anbox与渲染的机制和原理

session manager入口

session manager的入口函数在anbox/src/anbox/cmds/session_manager.cpp,我们阅读anbox源码时可以直接到这里开始就可以。进入构造函数。
先是处理一系列的启动参数,对渲染来说,主要参数是software-rendering,看它的Description{"Use software rendering instead of hardware accelerated GL rendering"},就是说使用软件渲染还是硬件渲染。
接下来直接到186行

    const auto should_force_software_rendering = utils::get_env_value("ANBOX_FORCE_SOFTWARE_RENDERING", "false");
    auto gl_driver = graphics::GLRendererServer::Config::Driver::Host;
    if (should_force_software_rendering == "true" || use_software_rendering_)
     gl_driver = graphics::GLRendererServer::Config::Driver::Software;

    graphics::GLRendererServer::Config renderer_config {
      gl_driver,
      single_window_
    };
    auto gl_server = std::make_shared<graphics::GLRendererServer>(renderer_config, window_manager);

    platform->set_window_manager(window_manager);
    platform->set_renderer(gl_server->renderer());
    window_manager->setup();

根据启动参数,决定使用软件渲染或硬件渲染,然后生成了一个GLRendererServer的共享指针。OK,那我们追进去,到anbox/src/anbox/graphics/gl_renderer_server.cpp。直接看构造函数:

GLRendererServer::GLRendererServer(const Config &config, const std::shared_ptr<wm::Manager> &wm)
    : renderer_(std::make_shared<::Renderer>()) {

  std::shared_ptr<LayerComposer::Strategy> composer_strategy;
  if (config.single_window)
    composer_strategy = std::make_shared<SingleWindowComposerStrategy>(wm);
  else
    composer_strategy = std::make_shared<MultiWindowComposerStrategy>(wm);

  composer_ = std::make_shared<LayerComposer>(renderer_, composer_strategy);

  auto gl_libs = emugl::default_gl_libraries();
  if (config.driver == Config::Driver::Software) {
    auto swiftshader_path = fs::path(utils::get_env_value("SWIFTSHADER_PATH"));
    const auto snap_path = utils::get_env_value("SNAP");
    if (!snap_path.empty())
      swiftshader_path = fs::path(snap_path) / "lib" / "anbox" / "swiftshader";
    if (!fs::exists(swiftshader_path))
      throw std::runtime_error("Software rendering is enabled, but SwiftShader library directory is not found.");

    gl_libs = std::vector<emugl::GLLibrary>{
      {emugl::GLLibrary::Type::EGL, (swiftshader_path / "libEGL.so").string()},
      {emugl::GLLibrary::Type::GLESv1, (swiftshader_path / "libGLES_CM.so").string()},
      {emugl::GLLibrary::Type::GLESv2, (swiftshader_path / "libGLESv2.so").string()},
    };
  }
  emugl_logger_struct log_funcs;
  log_funcs.coarse = logger_write;
  log_funcs.fine = logger_write;

  if (!emugl::initialize(gl_libs, &log_funcs, nullptr))
    BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));

  renderer_->initialize(0);

  registerRenderer(renderer_);
  registerLayerComposer(composer_);
}

先是根据使用的窗口策略生成对应的图层合成策略智能指针,LayerComposer这个模块里面就是把不同app的图层合成到同一个画布上,也就是第一篇所说的 虚拟一个Android的sufaceflinger
然后根据软件渲染还是硬件渲染读取对应的库函数,以软件渲染为例,anbox先去读取swiftshader的环境变量,如果存在,则将swiftshader库的路径设置为环境变量读取到的路径;然后anbox读取SNAP的环境变量,也就说说如果你的anbox是使用snap打包启动的,则直接去对应的路径下读取swiftshader的库。如果读取到了swiftshader库的路径,则在对应路径下读取libEGL.solibGLES_CM.solibGLESv2.so。即OpenGL ES对应的三个库文件。
然后去初始化这三个库文件,进入anbox/src/anbox/graphics/emugl/RenderApi.cpp

bool initialize(const std::vector<GLLibrary> &libs, emugl_logger_struct *log_funcs, logger_t crash_func) {
  set_emugl_crash_reporter(crash_func);
  if (log_funcs) {
    set_emugl_logger(log_funcs->coarse);
    set_emugl_cxt_logger(log_funcs->fine);
  }

  for (const auto &lib : libs) {
    const auto path = lib.path.c_str();
    switch (lib.type) {
    case GLLibrary::Type::EGL:
      if (!init_egl_dispatch(path))
        return false;
      break;
    case GLLibrary::Type::GLESv1:
      if (!gles1_dispatch_init(path, &s_gles1))
        return false;
      break;
    case GLLibrary::Type::GLESv2:
      if (!gles2_dispatch_init(path, &s_gles2))
        return false;
      break;
    default:
      break;
    }
  }

对三个库文件分别进入dispatch初始化,以init_egl_dispatch为例,其他两个库是一样的操作,进入anbox/external/android-emugl/host/libOpenGLESDispatch/EGLDispatch.cpp

bool init_egl_dispatch(const char *path) {
    const char *libName = getenv(egl_lib_env_var);
    if (!libName)
      libName = path;
    if (!libName)
      return false;

    char error[256];
    emugl::SharedLibrary *lib = emugl::SharedLibrary::open(libName, error, sizeof(error));
    if (!lib) {
        printf("Failed to open %s: [%s]\n", libName, error);
        return false;
    }

    LIST_RENDER_EGL_FUNCTIONS(RENDER_EGL_LOAD_FIELD)
    LIST_RENDER_EGL_EXTENSIONS_FUNCTIONS(RENDER_EGL_LOAD_OPTIONAL_FIELD)

    s_egl.initialized = true;

    return true;
}

打开对应路径,将egl需要用到的函数全部通过findSymboleglGetProcAddress的方式得到函数地址,方便后续直接调用。
这样就得到了OpenGL ES所有的函数地址了。
好,我们回到anbox/src/anbox/graphics/gl_renderer_server.cpp,初始化OpenGL函数后,会去初始化渲染器,来到了anbox/src/anbox/graphics/emugl/Renderer.cppinitialize,其实就是在display :0上初始化OpenGL ES相关的环境,跟我们平时使用OpenGL ES时候的操作基本上一致,不再多说了。
做完这些事情以后,算是gl_renderer_server的初始化就完成了,然后我们回到anbox/src/anbox/cmds/session_manager.cpp,下一步window_manager->setup();就要创建本地窗口了,其实就是我们看到的Android的窗口,所有Android 的画面都会显示在这个窗口上。
还是以单窗口为例,我们追到anbox/src/anbox/wm/single_window_manager.cpp

void SingleWindowManager::setup() {
  if (auto p = platform_.lock()) {
    window_ = p->create_window(0, window_size_, "Anbox - Android in a Box");
    if (!window_->attach())
      WARNING("Failed to attach window to renderer");
  } else {
    throw std::runtime_error("Can't create window as we don't have a platform abstraction");
  }
}

先是创建了一个Window的对象,然后调用这个对象的attach()函数,来到了anbox/src/anbox/wm/window.cpp

bool Window::attach() {
  if (!renderer_)
    return false;
  attached_ = renderer_->createNativeWindow(native_handle());
  return attached_;
}

可以看到,这里其实还是调用的renderer的创建本地窗口的方法。anbox/src/anbox/graphics/emugl/Renderer.cpp

RendererWindow *Renderer::createNativeWindow(
    EGLNativeWindowType native_window) {
  m_lock.lock();

  auto window = new RendererWindow;
  window->native_window = native_window;
  window->surface = s_egl.eglCreateWindowSurface(
      m_eglDisplay, m_eglConfig, window->native_window, nullptr);
  if (window->surface == EGL_NO_SURFACE) {
    delete window;
    m_lock.unlock();
    return nullptr;
  }

  if (!bindWindow_locked(window)) {
    s_egl.eglDestroySurface(m_eglDisplay, window->surface);
    delete window;
    m_lock.unlock();
    return nullptr;
  }

  s_gles2.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
                  GL_STENCIL_BUFFER_BIT);
  s_egl.eglSwapBuffers(m_eglDisplay, window->surface);

  unbind_locked();

  m_nativeWindows.insert({native_window, window});

  m_lock.unlock();

  return window;
}

可以看到,还是跟通常使用OpenGL ES一样,将本地窗口转化为OpenGL ES的窗口,供渲染器使用。
至此,渲染环境准备完毕,下一节我们从代码中看看Android中的OpenGL ES指令是如何传输到Anbox上使用的。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值