void vrend_renderer_create_sub_ctx(struct vrend_context *ctx, int sub_ctx_id)
{
   struct vrend_sub_context *sub;
   struct virgl_gl_ctx_param ctx_params;
   GLuint i;

   LIST_FOR_EACH_ENTRY(sub, &ctx->sub_ctxs, head) {
      if (sub->sub_ctx_id == sub_ctx_id) {
         return;
      }
   }

   sub = CALLOC_STRUCT(vrend_sub_context);
   if (!sub)
      return;

   ctx_params.shared = (ctx->ctx_id == 0 && sub_ctx_id == 0) ? false : true;
   ctx_params.major_ver = vrend_state.gl_major_ver;
   ctx_params.minor_ver = vrend_state.gl_minor_ver;
   sub->gl_context = vrend_clicbs->create_gl_context(0, &ctx_params);
   sub->parent = ctx;
   vrend_clicbs->make_current(sub->gl_context);

   /* enable if vrend_renderer_init function has done it as well */
   if (has_feature(feat_debug_cb)) {
      glDebugMessageCallback(vrend_debug_cb, NULL);
      glEnable(GL_DEBUG_OUTPUT);
      glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
   }

   sub->sub_ctx_id = sub_ctx_id;

   /* initialize the depth far_val to 1 */
   for (i = 0; i < PIPE_MAX_VIEWPORTS; i++) {
      sub->vps[i].far_val = 1.0;
   }

   if (!has_feature(feat_gles31_vertex_attrib_binding)) {
      glGenVertexArrays(1, &sub->vaoid);
      glBindVertexArray(sub->vaoid);
   }

   glGenFramebuffers(1, &sub->fb_id);
   glBindFramebuffer(GL_FRAMEBUFFER, sub->fb_id);
   glGenFramebuffers(2, sub->blit_fb_ids);

   for (int i = 0; i < VREND_PROGRAM_NQUEUES; ++i)
      list_inithead(&sub->gl_programs[i]);
   list_inithead(&sub->cs_programs);
   list_inithead(&sub->streamout_list);

   sub->object_hash = vrend_object_init_ctx_table();

   ctx->sub = sub;
   list_add(&sub->head, &ctx->sub_ctxs);
   if (sub_ctx_id == 0)
      ctx->sub0 = sub;

   vrend_set_tweak_from_env(&ctx->sub->tweaks);
}
void vrend_renderer_create_sub_ctx(struct vrend_context *ctx, int sub_ctx_id)
{
   struct vrend_sub_context *sub;
   struct virgl_gl_ctx_param ctx_params;
   GLuint i;

   LIST_FOR_EACH_ENTRY(sub, &ctx->sub_ctxs, head) {
      if (sub->sub_ctx_id == sub_ctx_id) {
         return;
      }
   }

   sub = CALLOC_STRUCT(vrend_sub_context);
   if (!sub)
      return;

   ctx_params.shared = (ctx->ctx_id == 0 && sub_ctx_id == 0) ? false : true;
   ctx_params.major_ver = vrend_state.gl_major_ver;
   ctx_params.minor_ver = vrend_state.gl_minor_ver;
   sub->gl_context = vrend_clicbs->create_gl_context(0, &ctx_params);
   sub->parent = ctx;
   vrend_clicbs->make_current(sub->gl_context);

    
   if (has_feature(feat_debug_cb)) {
      glDebugMessageCallback(vrend_debug_cb, NULL);
      glEnable(GL_DEBUG_OUTPUT);
      glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
   }

   sub->sub_ctx_id = sub_ctx_id;

    
   for (i = 0; i < PIPE_MAX_VIEWPORTS; i++) {
      sub->vps[i].far_val = 1.0;
   }

   if (!has_feature(feat_gles31_vertex_attrib_binding)) {
      glGenVertexArrays(1, &sub->vaoid);
      glBindVertexArray(sub->vaoid);
   }

   glGenFramebuffers(1, &sub->fb_id);
   glBindFramebuffer(GL_FRAMEBUFFER, sub->fb_id);
   glGenFramebuffers(2, sub->blit_fb_ids);

   for (int i = 0; i < VREND_PROGRAM_NQUEUES; ++i)
      list_inithead(&sub->gl_programs[i]);
   list_inithead(&sub->cs_programs);
   list_inithead(&sub->streamout_list);

   sub->object_hash = vrend_object_init_ctx_table();

   ctx->sub = sub;
   list_add(&sub->head, &ctx->sub_ctxs);
   if (sub_ctx_id == 0)
      ctx->sub0 = sub;

   vrend_set_tweak_from_env(&ctx->sub->tweaks);
}