void vrend_clear(struct vrend_context *ctx,
                 unsigned buffers,
                 const union pipe_color_union *color,
                 double depth, unsigned stencil)
{
   GLbitfield bits = 0;
   struct vrend_sub_context *sub_ctx = ctx->sub;

   if (ctx->in_error)
      return;

   if (ctx->ctx_switch_pending)
      vrend_finish_context_switch(ctx);

   vrend_update_frontface_state(sub_ctx);
   if (sub_ctx->stencil_state_dirty)
      vrend_update_stencil_state(sub_ctx);
   if (sub_ctx->scissor_state_dirty)
      vrend_update_scissor_state(sub_ctx);
   if (sub_ctx->viewport_state_dirty)
      vrend_update_viewport_state(sub_ctx);

   vrend_use_program(sub_ctx, 0);

   glDisable(GL_SCISSOR_TEST);

   float colorf[4];
   memcpy(colorf, color->f, sizeof(colorf));

   if (sub_ctx->nr_cbufs && sub_ctx->surf[0] &&
       vrend_resource_has_24bpp_internal_format(sub_ctx->surf[0]->texture) &&
       util_format_is_srgb(sub_ctx->surf[0]->format)) {
      VREND_DEBUG(dbg_tex, ctx,
                  "manually converting glClearColor from linear->srgb colorspace for EGL-backed framebuffer color attachment"
                  " (surface format is %s; resource format is %s)\n",
                  util_format_name(sub_ctx->surf[0]->format),
                  util_format_name(sub_ctx->surf[0]->texture->base.format));
      for (int i = 0; i < 3; ++i) // i < 3: don't convert alpha channel
         colorf[i] = vrend_color_convert_linear_to_srgb(colorf[i]);
   }

   if (buffers & PIPE_CLEAR_COLOR) {
      if (sub_ctx->nr_cbufs && sub_ctx->surf[0] && vrend_format_is_emulated_alpha(sub_ctx->surf[0]->format)) {
         glClearColor(colorf[3], 0.0, 0.0, 0.0);
      } else if (sub_ctx->nr_cbufs && sub_ctx->surf[0] && vrend_resource_is_emulated_bgra(sub_ctx->surf[0]->texture)) {
         VREND_DEBUG(dbg_bgra, ctx, "swizzling glClearColor() since rendering surface is an externally-stored BGR* resource\n");
         glClearColor(colorf[2], colorf[1], colorf[0], colorf[3]);
      } else {
         glClearColor(colorf[0], colorf[1], colorf[2], colorf[3]);
      }

      /* This function implements Gallium's full clear callback (st->pipe->clear) on the host. This
         callback requires no color component be masked. We must unmask all components before
         calling glClear* and restore the previous colormask afterwards, as Gallium expects. */
      if (sub_ctx->hw_blend_state.independent_blend_enable &&
          has_feature(feat_indep_blend)) {
         int i;
         for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
            glColorMaskIndexedEXT(i, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
      } else
         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
   }

   if (buffers & PIPE_CLEAR_DEPTH) {
      /* gallium clears don't respect depth mask */
      glDepthMask(GL_TRUE);
      if (vrend_state.use_gles) {
         if (0.0f < depth && depth > 1.0f) {
            // Only warn, it is clamped by the function.
            report_gles_warn(ctx, GLES_WARN_DEPTH_CLEAR);
         }
         glClearDepthf(depth);
      } else {
         glClearDepth(depth);
      }
   }

   if (buffers & PIPE_CLEAR_STENCIL) {
      glStencilMask(~0u);
      glClearStencil(stencil);
   }

   if (sub_ctx->hw_rs_state.rasterizer_discard)
       glDisable(GL_RASTERIZER_DISCARD);

   if (buffers & PIPE_CLEAR_COLOR) {
      uint32_t mask = 0;
      int i;
      for (i = 0; i < sub_ctx->nr_cbufs; i++) {
         if (sub_ctx->surf[i])
            mask |= (1 << i);
      }
      if (mask != (buffers >> 2)) {
         mask = buffers >> 2;
         while (mask) {
            i = u_bit_scan(&mask);
            if (i < PIPE_MAX_COLOR_BUFS && sub_ctx->surf[i] && util_format_is_pure_uint(sub_ctx->surf[i] && sub_ctx->surf[i]->format))
               glClearBufferuiv(GL_COLOR,
                                i, (GLuint *)colorf);
            else if (i < PIPE_MAX_COLOR_BUFS && sub_ctx->surf[i] && util_format_is_pure_sint(sub_ctx->surf[i] && sub_ctx->surf[i]->format))
               glClearBufferiv(GL_COLOR,
                                i, (GLint *)colorf);
            else
               glClearBufferfv(GL_COLOR,
                                i, (GLfloat *)colorf);
         }
      }
      else
         bits |= GL_COLOR_BUFFER_BIT;
   }
   if (buffers & PIPE_CLEAR_DEPTH)
      bits |= GL_DEPTH_BUFFER_BIT;
   if (buffers & PIPE_CLEAR_STENCIL)
      bits |= GL_STENCIL_BUFFER_BIT;

   if (bits)
      glClear(bits);

   /* Is it really necessary to restore the old states? The only reason we
    * get here is because the guest cleared all those states but gallium
    * didn't forward them before calling the clear command
    */
   if (sub_ctx->hw_rs_state.rasterizer_discard)
       glEnable(GL_RASTERIZER_DISCARD);

   if (buffers & PIPE_CLEAR_DEPTH) {
      if (!sub_ctx->dsa_state.depth.writemask)
         glDepthMask(GL_FALSE);
   }

   /* Restore previous stencil buffer write masks for both front and back faces */
   if (buffers & PIPE_CLEAR_STENCIL) {
      glStencilMaskSeparate(GL_FRONT, sub_ctx->dsa_state.stencil[0].writemask);
      glStencilMaskSeparate(GL_BACK, sub_ctx->dsa_state.stencil[1].writemask);
   }

   /* Restore previous colormask */
   if (buffers & PIPE_CLEAR_COLOR) {
      if (sub_ctx->hw_blend_state.independent_blend_enable &&
          has_feature(feat_indep_blend)) {
         int i;
         for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
            struct pipe_blend_state *blend = &sub_ctx->hw_blend_state;
            glColorMaskIndexedEXT(i, blend->rt[i].colormask & PIPE_MASK_R ? GL_TRUE : GL_FALSE,
                                  blend->rt[i].colormask & PIPE_MASK_G ? GL_TRUE : GL_FALSE,
                                  blend->rt[i].colormask & PIPE_MASK_B ? GL_TRUE : GL_FALSE,
                                  blend->rt[i].colormask & PIPE_MASK_A ? GL_TRUE : GL_FALSE);
         }
      } else {
         glColorMask(sub_ctx->hw_blend_state.rt[0].colormask & PIPE_MASK_R ? GL_TRUE : GL_FALSE,
                     sub_ctx->hw_blend_state.rt[0].colormask & PIPE_MASK_G ? GL_TRUE : GL_FALSE,
                     sub_ctx->hw_blend_state.rt[0].colormask & PIPE_MASK_B ? GL_TRUE : GL_FALSE,
                     sub_ctx->hw_blend_state.rt[0].colormask & PIPE_MASK_A ? GL_TRUE : GL_FALSE);
      }
   }
   if (sub_ctx->hw_rs_state.scissor)
      glEnable(GL_SCISSOR_TEST);
   else
      glDisable(GL_SCISSOR_TEST);
}