void vrend_fb_bind_texture_id(struct vrend_resource *res,
                              int id, int idx, uint32_t level,
                              uint32_t layer, uint32_t samples)
{
   const struct util_format_description *desc = util_format_description(res->base.format);
   GLenum attachment = GL_COLOR_ATTACHMENT0 + idx;

   debug_texture(__func__, res);

   if (vrend_format_is_ds(res->base.format)) {
      if (util_format_has_stencil(desc)) {
         if (util_format_has_depth(desc))
            attachment = GL_DEPTH_STENCIL_ATTACHMENT;
         else
            attachment = GL_STENCIL_ATTACHMENT;
      } else
         attachment = GL_DEPTH_ATTACHMENT;
   }

   switch (res->target) {
   case GL_TEXTURE_1D_ARRAY:
   case GL_TEXTURE_2D_ARRAY:
   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
   case GL_TEXTURE_CUBE_MAP_ARRAY:
      if (layer == 0xffffffff)
         glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                              id, level);
      else
         glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
                                   id, level, layer);
      break;
   case GL_TEXTURE_3D:
      if (layer == 0xffffffff)
         glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                              id, level);
      else if (vrend_state.use_gles)
         glFramebufferTexture3DOES(GL_FRAMEBUFFER, attachment,
                                   res->target, id, level, layer);
      else
         glFramebufferTexture3D(GL_FRAMEBUFFER, attachment,
                                res->target, id, level, layer);
      break;
   case GL_TEXTURE_CUBE_MAP:
      if (layer == 0xffffffff)
         glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                              id, level);
      else
         vrend_framebuffer_texture_2d(res, GL_FRAMEBUFFER, attachment,
                                      GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer,
                                      id, level, samples);
      break;
   case GL_TEXTURE_1D:
      glFramebufferTexture1D(GL_FRAMEBUFFER, attachment,
                             res->target, id, level);
      break;
   case GL_TEXTURE_2D:
   default:
      vrend_framebuffer_texture_2d(res, GL_FRAMEBUFFER, attachment,
                                   res->target, id, level, samples);
      break;
   }

   if (attachment == GL_DEPTH_ATTACHMENT) {
      switch (res->target) {
      case GL_TEXTURE_1D:
         glFramebufferTexture1D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                                GL_TEXTURE_1D, 0, 0);
         break;
      case GL_TEXTURE_2D:
      default:
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                                GL_TEXTURE_2D, 0, 0);
         break;
      }
   }
}
void vrend_fb_bind_texture_id(struct vrend_resource *res,
                              int id, int idx, uint32_t level,
                              uint32_t layer, uint32_t samples)
{
   const struct util_format_description *desc = util_format_description(res->base.format);
   GLenum attachment = GL_COLOR_ATTACHMENT0 + idx;

   debug_texture(__func__, res);

   if (vrend_format_is_ds(res->base.format)) {
      if (util_format_has_stencil(desc)) {
         if (util_format_has_depth(desc))
            attachment = GL_DEPTH_STENCIL_ATTACHMENT;
         else
            attachment = GL_STENCIL_ATTACHMENT;
      } else
         attachment = GL_DEPTH_ATTACHMENT;
   }

   switch (res->target) {
   case GL_TEXTURE_1D_ARRAY:
   case GL_TEXTURE_2D_ARRAY:
   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
   case GL_TEXTURE_CUBE_MAP_ARRAY:
      if (layer == 0xffffffff)
         glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                              id, level);
      else
         glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
                                   id, level, layer);
      break;
   case GL_TEXTURE_3D:
      if (layer == 0xffffffff)
         glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                              id, level);
      else if (vrend_state.use_gles)
         glFramebufferTexture3DOES(GL_FRAMEBUFFER, attachment,
                                   res->target, id, level, layer);
      else
         glFramebufferTexture3D(GL_FRAMEBUFFER, attachment,
                                res->target, id, level, layer);
      break;
   case GL_TEXTURE_CUBE_MAP:
      if (layer == 0xffffffff)
         glFramebufferTexture(GL_FRAMEBUFFER, attachment,
                              id, level);
      else
         vrend_framebuffer_texture_2d(res, GL_FRAMEBUFFER, attachment,
                                      GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer,
                                      id, level, samples);
      break;
   case GL_TEXTURE_1D:
      glFramebufferTexture1D(GL_FRAMEBUFFER, attachment,
                             res->target, id, level);
      break;
   case GL_TEXTURE_2D:
   default:
      vrend_framebuffer_texture_2d(res, GL_FRAMEBUFFER, attachment,
                                   res->target, id, level, samples);
      break;
   }

   if (attachment == GL_DEPTH_ATTACHMENT) {
      switch (res->target) {
      case GL_TEXTURE_1D:
         glFramebufferTexture1D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                                GL_TEXTURE_1D, 0, 0);
         break;
      case GL_TEXTURE_2D:
      default:
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
                                GL_TEXTURE_2D, 0, 0);
         break;
      }
   }
}