int vrend_create_surface(struct vrend_context *ctx,
                         uint32_t handle,
                         uint32_t res_handle, uint32_t format,
                         uint32_t val0, uint32_t val1,
                         uint32_t nr_samples)
{
   struct vrend_surface *surf;
   struct vrend_resource *res;
   uint32_t ret_handle;

   if (format >= PIPE_FORMAT_COUNT) {
      return EINVAL;
   }

   res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
   if (!res) {
      vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
      return EINVAL;
   }

   surf = CALLOC_STRUCT(vrend_surface);
   if (!surf)
      return ENOMEM;

   surf->res_handle = res_handle;
   surf->format = format;

   surf->val0 = val0;
   surf->val1 = val1;
   surf->id = res->id;
   surf->nr_samples = nr_samples;

   if (!has_bit(res->storage_bits, VREND_STORAGE_GL_BUFFER) &&
         has_bit(res->storage_bits, VREND_STORAGE_GL_IMMUTABLE) &&
         has_feature(feat_texture_view)) {
      /* We don't need texture views for buffer objects.
       * Otherwise we only need a texture view if the
       * a) formats differ between the surface and base texture
       * b) we need to map a sub range > 1 layer to a surface,
       * GL can make a single layer fine without a view, and it
       * can map the whole texure fine. In those cases we don't
       * create a texture view.
       */
      int first_layer = surf->val1 & 0xffff;
      int last_layer = (surf->val1 >> 16) & 0xffff;

      if ((first_layer != last_layer &&
           (first_layer != 0 || (last_layer != (int)util_max_layer(&res->base, surf->val0)))) ||
          surf->format != res->base.format) {
         GLenum target = res->target;
         GLenum internalformat = tex_conv_table[format].internalformat;

         if (vrend_resource_has_24bpp_internal_format(res))
            internalformat = GL_RGB8;

         VREND_DEBUG(dbg_tex, ctx, "Create texture view from %s for %s\n",
                     util_format_name(res->base.format),
                     util_format_name(surf->format));

         glGenTextures(1, &surf->id);
         if (vrend_state.use_gles) {
            if (target == GL_TEXTURE_RECTANGLE_NV ||
                target == GL_TEXTURE_1D)
               target = GL_TEXTURE_2D;
            else if (target == GL_TEXTURE_1D_ARRAY)
               target = GL_TEXTURE_2D_ARRAY;
         }

         glTextureView(surf->id, target, res->id, internalformat,
                       0, res->base.last_level + 1,
                       first_layer, last_layer - first_layer + 1);
      }
   }

   pipe_reference_init(&surf->reference, 1);

   vrend_resource_reference(&surf->texture, res);

   ret_handle = vrend_renderer_object_insert(ctx, surf, handle, VIRGL_OBJECT_SURFACE);
   if (ret_handle == 0) {
      FREE(surf);
      return ENOMEM;
   }
   return 0;
}
int vrend_create_surface(struct vrend_context *ctx,
                         uint32_t handle,
                         uint32_t res_handle, uint32_t format,
                         uint32_t val0, uint32_t val1,
                         uint32_t nr_samples)
{
   struct vrend_surface *surf;
   struct vrend_resource *res;
   uint32_t ret_handle;

   if (format >= PIPE_FORMAT_COUNT) {
      return EINVAL;
   }

   res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
   if (!res) {
      vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
      return EINVAL;
   }

   surf = CALLOC_STRUCT(vrend_surface);
   if (!surf)
      return ENOMEM;

   surf->res_handle = res_handle;
   surf->format = format;

   surf->val0 = val0;
   surf->val1 = val1;
   surf->id = res->id;
   surf->nr_samples = nr_samples;

   if (!has_bit(res->storage_bits, VREND_STORAGE_GL_BUFFER) &&
         has_bit(res->storage_bits, VREND_STORAGE_GL_IMMUTABLE) &&
         has_feature(feat_texture_view)) {
       
      int first_layer = surf->val1 & 0xffff;
      int last_layer = (surf->val1 >> 16) & 0xffff;

      if ((first_layer != last_layer &&
           (first_layer != 0 || (last_layer != (int)util_max_layer(&res->base, surf->val0)))) ||
          surf->format != res->base.format) {
         GLenum target = res->target;
         GLenum internalformat = tex_conv_table[format].internalformat;

         if (vrend_resource_has_24bpp_internal_format(res))
            internalformat = GL_RGB8;

         VREND_DEBUG(dbg_tex, ctx, "Create texture view from %s for %s\n",
                     util_format_name(res->base.format),
                     util_format_name(surf->format));

         glGenTextures(1, &surf->id);
         if (vrend_state.use_gles) {
            if (target == GL_TEXTURE_RECTANGLE_NV ||
                target == GL_TEXTURE_1D)
               target = GL_TEXTURE_2D;
            else if (target == GL_TEXTURE_1D_ARRAY)
               target = GL_TEXTURE_2D_ARRAY;
         }

         glTextureView(surf->id, target, res->id, internalformat,
                       0, res->base.last_level + 1,
                       first_layer, last_layer - first_layer + 1);
      }
   }

   pipe_reference_init(&surf->reference, 1);

   vrend_resource_reference(&surf->texture, res);

   ret_handle = vrend_renderer_object_insert(ctx, surf, handle, VIRGL_OBJECT_SURFACE);
   if (ret_handle == 0) {
      FREE(surf);
      return ENOMEM;
   }
   return 0;
}