void vrend_set_single_sampler_view(struct vrend_context *ctx,
                                   uint32_t shader_type,
                                   uint32_t index,
                                   uint32_t handle)
{
   struct vrend_sampler_view *view = NULL;
   struct vrend_texture *tex;

   if (handle) {
      view = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_SAMPLER_VIEW);
      if (!view) {
         ctx->sub->views[shader_type].views[index] = NULL;
         vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle);
         return;
      }
      if (ctx->sub->views[shader_type].views[index] == view) {
         return;
      }
      /* we should have a reference to this texture taken at create time */
      tex = (struct vrend_texture *)view->texture;
      if (!tex) {
         return;
      }

      ctx->sub->sampler_views_dirty[shader_type] |= 1u << index;

      if (!has_bit(view->texture->storage_bits, VREND_STORAGE_GL_BUFFER)) {
         if (view->texture->id == view->id) {
            glBindTexture(view->target, view->id);

            if (util_format_is_depth_or_stencil(view->format)) {
               if (vrend_state.use_core_profile == false) {
                  /* setting depth texture mode is deprecated in core profile */
                  if (view->depth_texture_mode != GL_RED) {
                     glTexParameteri(view->texture->target, GL_DEPTH_TEXTURE_MODE, GL_RED);
                     view->depth_texture_mode = GL_RED;
                  }
               }
               if (has_feature(feat_stencil_texturing)) {
                  const struct util_format_description *desc = util_format_description(view->format);
                  if (!util_format_has_depth(desc)) {
                     glTexParameteri(view->texture->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
                  } else {
                     glTexParameteri(view->texture->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
                  }
               }
            }

            GLuint base_level = view->val1 & 0xff;
            GLuint max_level = (view->val1 >> 8) & 0xff;
            view->levels = max_level - base_level + 1;

            if (tex->cur_base != base_level) {
               glTexParameteri(view->texture->target, GL_TEXTURE_BASE_LEVEL, base_level);
               tex->cur_base = base_level;
            }
            if (tex->cur_max != max_level) {
               glTexParameteri(view->texture->target, GL_TEXTURE_MAX_LEVEL, max_level);
               tex->cur_max = max_level;
            }
            if (memcmp(tex->cur_swizzle, view->gl_swizzle, 4 * sizeof(GLint))) {
               if (vrend_state.use_gles) {
                  for (unsigned int i = 0; i < 4; ++i) {
                     if (tex->cur_swizzle[i] != view->gl_swizzle[i]) {
                         glTexParameteri(view->texture->target, GL_TEXTURE_SWIZZLE_R + i, view->gl_swizzle[i]);
                     }
                  }
               } else
                  glTexParameteriv(view->texture->target, GL_TEXTURE_SWIZZLE_RGBA, view->gl_swizzle);
               memcpy(tex->cur_swizzle, view->gl_swizzle, 4 * sizeof(GLint));
            }

            if (tex->cur_srgb_decode != view->srgb_decode && util_format_is_srgb(tex->base.base.format)) {
               if (has_feature(feat_samplers))
                  ctx->sub->sampler_views_dirty[shader_type] |= (1u << index);
               else if (has_feature(feat_texture_srgb_decode)) {
                  glTexParameteri(view->texture->target, GL_TEXTURE_SRGB_DECODE_EXT,
                                  view->srgb_decode);
                  tex->cur_srgb_decode = view->srgb_decode;
               }
            }
         }
      } else {
         GLenum internalformat;

         if (!view->texture->tbo_tex_id)
            glGenTextures(1, &view->texture->tbo_tex_id);

         glBindTexture(GL_TEXTURE_BUFFER, view->texture->tbo_tex_id);
         internalformat = tex_conv_table[view->format].internalformat;
         if (has_feature(feat_texture_buffer_range)) {
            unsigned offset = view->val0;
            unsigned size = view->val1 - view->val0 + 1;
            int blsize = util_format_get_blocksize(view->format);

            offset *= blsize;
            size *= blsize;
            glTexBufferRange(GL_TEXTURE_BUFFER, internalformat, view->texture->id, offset, size);
         } else
            glTexBuffer(GL_TEXTURE_BUFFER, internalformat, view->texture->id);
      }
   }

   vrend_sampler_view_reference(&ctx->sub->views[shader_type].views[index], view);
}