void vrend_launch_grid(struct vrend_context *ctx,
                       UNUSED uint32_t *block,
                       uint32_t *grid,
                       uint32_t indirect_handle,
                       uint32_t indirect_offset)
{
   bool new_program = false;
   struct vrend_resource *indirect_res = NULL;

   if (!has_feature(feat_compute_shader))
      return;

    struct vrend_sub_context *sub_ctx = ctx->sub;

   if (sub_ctx->cs_shader_dirty) {
      struct vrend_linked_shader_program *prog;
      bool cs_dirty;

      sub_ctx->cs_shader_dirty = false;

      if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]) {
         vrend_printf("dropping rendering due to missing shaders: %s\n", ctx->debug_name);
         return;
      }

      vrend_shader_select(sub_ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE], &cs_dirty);
      if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current) {
         vrend_printf( "failure to select compute shader variant: %s\n", ctx->debug_name);
         return;
      }
      if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->is_compiled) {
         if(!vrend_compile_shader(sub_ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current)) {
            vrend_printf( "failure to compile compute shader variant: %s\n", ctx->debug_name);
            return;
         }
      }
      if (sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id != (GLuint)sub_ctx->prog_ids[PIPE_SHADER_COMPUTE]) {
         prog = lookup_cs_shader_program(ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id);
         if (!prog) {
            prog = add_cs_shader_program(ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current);
            if (!prog)
               return;
         }
      } else
         prog = sub_ctx->prog;

      if (sub_ctx->prog != prog) {
         new_program = true;
         sub_ctx->prog_ids[PIPE_SHADER_VERTEX] = 0;
         sub_ctx->prog_ids[PIPE_SHADER_COMPUTE] = sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id;
         sub_ctx->prog = prog;
         prog->ref_context = sub_ctx;
      }
      sub_ctx->shader_dirty = true;
   }

   if (!sub_ctx->prog) {
      vrend_printf("%s: Skipping compute shader execution due to missing shaders: %s\n",
                   __func__, ctx->debug_name);
      return;
   }

   vrend_use_program(sub_ctx, sub_ctx->prog->id);

   vrend_draw_bind_ubo_shader(sub_ctx, PIPE_SHADER_COMPUTE, 0);
   vrend_draw_bind_const_shader(sub_ctx, PIPE_SHADER_COMPUTE, new_program);
   vrend_draw_bind_samplers_shader(sub_ctx, PIPE_SHADER_COMPUTE, 0);
   vrend_draw_bind_images_shader(sub_ctx, PIPE_SHADER_COMPUTE);
   vrend_draw_bind_ssbo_shader(sub_ctx, PIPE_SHADER_COMPUTE);
   vrend_draw_bind_abo_shader(sub_ctx);

   if (indirect_handle) {
      indirect_res = vrend_renderer_ctx_res_lookup(ctx, indirect_handle);
      if (!indirect_res) {
         vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, indirect_handle);
         return;
      }
   }

   if (indirect_res)
      glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirect_res->id);
   else
      glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);

   if (indirect_res) {
      glDispatchComputeIndirect(indirect_offset);
   } else {
      glDispatchCompute(grid[0], grid[1], grid[2]);
   }
}
void vrend_launch_grid(struct vrend_context *ctx,
                       UNUSED uint32_t *block,
                       uint32_t *grid,
                       uint32_t indirect_handle,
                       uint32_t indirect_offset)
{
   bool new_program = false;
   struct vrend_resource *indirect_res = NULL;

   if (!has_feature(feat_compute_shader))
      return;

    struct vrend_sub_context *sub_ctx = ctx->sub;

   if (sub_ctx->cs_shader_dirty) {
      struct vrend_linked_shader_program *prog;
      bool cs_dirty;

      sub_ctx->cs_shader_dirty = false;

      if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]) {
         vrend_printf("dropping rendering due to missing shaders: %s\n", ctx->debug_name);
         return;
      }

      vrend_shader_select(sub_ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE], &cs_dirty);
      if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current) {
         vrend_printf( "failure to select compute shader variant: %s\n", ctx->debug_name);
         return;
      }
      if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->is_compiled) {
         if(!vrend_compile_shader(sub_ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current)) {
            vrend_printf( "failure to compile compute shader variant: %s\n", ctx->debug_name);
            return;
         }
      }
      if (sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id != (GLuint)sub_ctx->prog_ids[PIPE_SHADER_COMPUTE]) {
         prog = lookup_cs_shader_program(ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id);
         if (!prog) {
            prog = add_cs_shader_program(ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current);
            if (!prog)
               return;
         }
      } else
         prog = sub_ctx->prog;

      if (sub_ctx->prog != prog) {
         new_program = true;
         sub_ctx->prog_ids[PIPE_SHADER_VERTEX] = 0;
         sub_ctx->prog_ids[PIPE_SHADER_COMPUTE] = sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id;
         sub_ctx->prog = prog;
         prog->ref_context = sub_ctx;
      }
      sub_ctx->shader_dirty = true;
   }

   if (!sub_ctx->prog) {
      vrend_printf("%s: Skipping compute shader execution due to missing shaders: %s\n",
                   __func__, ctx->debug_name);
      return;
   }

   vrend_use_program(sub_ctx, sub_ctx->prog->id);

   vrend_draw_bind_ubo_shader(sub_ctx, PIPE_SHADER_COMPUTE, 0);
   vrend_draw_bind_const_shader(sub_ctx, PIPE_SHADER_COMPUTE, new_program);
   vrend_draw_bind_samplers_shader(sub_ctx, PIPE_SHADER_COMPUTE, 0);
   vrend_draw_bind_images_shader(sub_ctx, PIPE_SHADER_COMPUTE);
   vrend_draw_bind_ssbo_shader(sub_ctx, PIPE_SHADER_COMPUTE);
   vrend_draw_bind_abo_shader(sub_ctx);

   if (indirect_handle) {
      indirect_res = vrend_renderer_ctx_res_lookup(ctx, indirect_handle);
      if (!indirect_res) {
         vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, indirect_handle);
         return;
      }
   }

   if (indirect_res)
      glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirect_res->id);
   else
      glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);

   if (indirect_res) {
      glDispatchComputeIndirect(indirect_offset);
   } else {
      glDispatchCompute(grid[0], grid[1], grid[2]);
   }
}