static void vrend_hw_emit_framebuffer_state(struct vrend_sub_context *sub_ctx)
{
   static const GLenum buffers[8] = {
      GL_COLOR_ATTACHMENT0,
      GL_COLOR_ATTACHMENT1,
      GL_COLOR_ATTACHMENT2,
      GL_COLOR_ATTACHMENT3,
      GL_COLOR_ATTACHMENT4,
      GL_COLOR_ATTACHMENT5,
      GL_COLOR_ATTACHMENT6,
      GL_COLOR_ATTACHMENT7,
   };

   if (sub_ctx->nr_cbufs == 0) {
      glReadBuffer(GL_NONE);
      if (has_feature(feat_srgb_write_control)) {
         glDisable(GL_FRAMEBUFFER_SRGB_EXT);
         sub_ctx->framebuffer_srgb_enabled = false;
      }
   } else if (has_feature(feat_srgb_write_control)) {
      struct vrend_surface *surf = NULL;
      bool use_srgb = false;
      int i;
      for (i = 0; i < sub_ctx->nr_cbufs; i++) {
         if (sub_ctx->surf[i]) {
            surf = sub_ctx->surf[i];
            if (util_format_is_srgb(surf->format)) {
               use_srgb = true;
               break;
            }
         }
      }
      if (use_srgb) {
         glEnable(GL_FRAMEBUFFER_SRGB_EXT);
      } else {
         glDisable(GL_FRAMEBUFFER_SRGB_EXT);
      }
      sub_ctx->framebuffer_srgb_enabled = use_srgb;
   }

   sub_ctx->swizzle_output_rgb_to_bgr = 0;
   sub_ctx->convert_linear_to_srgb_on_write = 0;
   for (int i = 0; i < sub_ctx->nr_cbufs; i++) {
      if (sub_ctx->surf[i]) {
         struct vrend_surface *surf = sub_ctx->surf[i];
         if (vrend_resource_is_emulated_bgra(surf->texture)) {
            VREND_DEBUG(dbg_bgra, sub_ctx->parent, "swizzling output for 0x%x (surface format is %s; resource format is %s)\n",
                         i, util_format_name(surf->format), util_format_name(surf->texture->base.format));
            sub_ctx->swizzle_output_rgb_to_bgr |= 1 << i;
         }

         /* [R8G8B8|B8G8R8]X8_UNORM formatted resources imported to mesa as EGL images occupy 24bpp instead of
          * more common 32bpp (with an ignored alpha channel). GL_RGB8 internal format must be specified when
          * interacting with these textures in the host driver. Unfortunately, GL_SRGB8 is not guaranteed to
          * be color-renderable on either GL or GLES, and is typically not supported. Thus, rendering to such
          * surfaces by using an SRGB texture view will have no colorspace conversion effects.
          * To work around this, manual colorspace conversion is used instead in the fragment shader and
          * during glClearColor() setting.
          */
         if (vrend_resource_has_24bpp_internal_format(surf->texture) && util_format_is_srgb(surf->format)) {
            VREND_DEBUG(dbg_tex, sub_ctx->parent,
                        "manually converting linear->srgb for EGL-backed framebuffer color attachment 0x%x"
                        " (surface format is %s; resource format is %s)\n",
                        i, util_format_name(surf->format), util_format_name(surf->texture->base.format));
            sub_ctx->convert_linear_to_srgb_on_write |= 1 << i;
         }
      }
   }

   glDrawBuffers(sub_ctx->nr_cbufs, buffers);
}
static void vrend_hw_emit_framebuffer_state(struct vrend_sub_context *sub_ctx)
{
   static const GLenum buffers[8] = {
      GL_COLOR_ATTACHMENT0,
      GL_COLOR_ATTACHMENT1,
      GL_COLOR_ATTACHMENT2,
      GL_COLOR_ATTACHMENT3,
      GL_COLOR_ATTACHMENT4,
      GL_COLOR_ATTACHMENT5,
      GL_COLOR_ATTACHMENT6,
      GL_COLOR_ATTACHMENT7,
   };

   if (sub_ctx->nr_cbufs == 0) {
      glReadBuffer(GL_NONE);
      if (has_feature(feat_srgb_write_control)) {
         glDisable(GL_FRAMEBUFFER_SRGB_EXT);
         sub_ctx->framebuffer_srgb_enabled = false;
      }
   } else if (has_feature(feat_srgb_write_control)) {
      struct vrend_surface *surf = NULL;
      bool use_srgb = false;
      int i;
      for (i = 0; i < sub_ctx->nr_cbufs; i++) {
         if (sub_ctx->surf[i]) {
            surf = sub_ctx->surf[i];
            if (util_format_is_srgb(surf->format)) {
               use_srgb = true;
               break;
            }
         }
      }
      if (use_srgb) {
         glEnable(GL_FRAMEBUFFER_SRGB_EXT);
      } else {
         glDisable(GL_FRAMEBUFFER_SRGB_EXT);
      }
      sub_ctx->framebuffer_srgb_enabled = use_srgb;
   }

   sub_ctx->swizzle_output_rgb_to_bgr = 0;
   sub_ctx->convert_linear_to_srgb_on_write = 0;
   for (int i = 0; i < sub_ctx->nr_cbufs; i++) {
      if (sub_ctx->surf[i]) {
         struct vrend_surface *surf = sub_ctx->surf[i];
         if (vrend_resource_is_emulated_bgra(surf->texture)) {
            VREND_DEBUG(dbg_bgra, sub_ctx->parent, "swizzling output for 0x%x (surface format is %s; resource format is %s)\n",
                         i, util_format_name(surf->format), util_format_name(surf->texture->base.format));
            sub_ctx->swizzle_output_rgb_to_bgr |= 1 << i;
         }

          
         if (vrend_resource_has_24bpp_internal_format(surf->texture) && util_format_is_srgb(surf->format)) {
            VREND_DEBUG(dbg_tex, sub_ctx->parent,
                        "manually converting linear->srgb for EGL-backed framebuffer color attachment 0x%x"
                        " (surface format is %s; resource format is %s)\n",
                        i, util_format_name(surf->format), util_format_name(surf->texture->base.format));
            sub_ctx->convert_linear_to_srgb_on_write |= 1 << i;
         }
      }
   }

   glDrawBuffers(sub_ctx->nr_cbufs, buffers);
}