int vrend_renderer_init(struct vrend_if_cbs *cbs, uint32_t flags)
{
   bool gles;
   int gl_ver;
   virgl_gl_context gl_context;
   struct virgl_gl_ctx_param ctx_params;

   if (!vrend_state.inited) {
      vrend_state.inited = true;
      vrend_object_init_resource_table();
      vrend_clicbs = cbs;
      /* Give some defaults to be able to run the tests */
      vrend_state.max_texture_2d_size =
            vrend_state.max_texture_3d_size =
            vrend_state.max_texture_cube_size = 16384;
   }

#ifndef NDEBUG
   vrend_init_debug_flags();
#endif

   ctx_params.shared = false;
   for (uint32_t i = 0; i < ARRAY_SIZE(gl_versions); i++) {
      ctx_params.major_ver = gl_versions[i].major;
      ctx_params.minor_ver = gl_versions[i].minor;

      gl_context = vrend_clicbs->create_gl_context(0, &ctx_params);
      if (gl_context)
         break;
   }

   vrend_clicbs->make_current(gl_context);
   gl_ver = epoxy_gl_version();

   /* enable error output as early as possible */
   if (vrend_use_debug_cb && epoxy_has_gl_extension("GL_KHR_debug")) {
      glDebugMessageCallback(vrend_debug_cb, NULL);
      glEnable(GL_DEBUG_OUTPUT);
      glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
      set_feature(feat_debug_cb);
   }

   /* make sure you have the latest version of libepoxy */
   gles = epoxy_is_desktop_gl() == 0;

   vrend_state.gl_major_ver = gl_ver / 10;
   vrend_state.gl_minor_ver = gl_ver % 10;

   if (gles) {
      vrend_printf( "gl_version %d - es profile enabled\n", gl_ver);
      vrend_state.use_gles = true;
      /* for now, makes the rest of the code use the most GLES 3.x like path */
      vrend_state.use_core_profile = 1;
   } else if (gl_ver > 30 && !epoxy_has_gl_extension("GL_ARB_compatibility")) {
      vrend_printf( "gl_version %d - core profile enabled\n", gl_ver);
      vrend_state.use_core_profile = 1;
   } else {
      vrend_printf( "gl_version %d - compat profile\n", gl_ver);
   }

   init_features(gles ? 0 : gl_ver,
                 gles ? gl_ver : 0);

   vrend_state.features[feat_srgb_write_control] &= virgl_has_gl_colorspace();

   glGetIntegerv(GL_MAX_DRAW_BUFFERS, (GLint *) &vrend_state.max_draw_buffers);

   if (!has_feature(feat_arb_robustness) &&
       !has_feature(feat_gles_khr_robustness)) {
      vrend_printf("WARNING: running without ARB/KHR robustness in place may crash\n");
   }

   /* callbacks for when we are cleaning up the object table */
   vrend_resource_set_destroy_callback(vrend_destroy_resource_object);
   vrend_object_set_destroy_callback(VIRGL_OBJECT_QUERY, vrend_destroy_query_object);
   vrend_object_set_destroy_callback(VIRGL_OBJECT_SURFACE, vrend_destroy_surface_object);
   vrend_object_set_destroy_callback(VIRGL_OBJECT_SHADER, vrend_destroy_shader_object);
   vrend_object_set_destroy_callback(VIRGL_OBJECT_SAMPLER_VIEW, vrend_destroy_sampler_view_object);
   vrend_object_set_destroy_callback(VIRGL_OBJECT_STREAMOUT_TARGET, vrend_destroy_so_target_object);
   vrend_object_set_destroy_callback(VIRGL_OBJECT_SAMPLER_STATE, vrend_destroy_sampler_state_object);
   vrend_object_set_destroy_callback(VIRGL_OBJECT_VERTEX_ELEMENTS, vrend_destroy_vertex_elements_object);

   /* disable for format testing, spews a lot of errors */
   if (has_feature(feat_debug_cb)) {
      glDisable(GL_DEBUG_OUTPUT);
   }

   vrend_state.bgra_srgb_emulation_loaded = false;
   vrend_build_format_list_common();

   if (vrend_state.use_gles) {
      vrend_build_format_list_gles();
   } else {
      vrend_build_format_list_gl();
   }

   vrend_check_texture_storage(tex_conv_table);

   /* disable for format testing */
   if (has_feature(feat_debug_cb)) {
      glDisable(GL_DEBUG_OUTPUT);
   }

   vrend_clicbs->destroy_gl_context(gl_context);
   list_inithead(&vrend_state.fence_list);
   list_inithead(&vrend_state.fence_wait_list);
   list_inithead(&vrend_state.waiting_query_list);
   list_inithead(&vrend_state.active_ctx_list);
   /* create 0 context */
   vrend_renderer_context_create_internal(0, strlen("HOST"), "HOST");

   vrend_state.eventfd = -1;
   if (flags & VREND_USE_THREAD_SYNC) {
      vrend_renderer_use_threaded_sync();
   }

   return 0;
}