void vg_validate_state(struct vg_context *ctx)
{
   struct st_framebuffer *stfb = ctx->draw_buffer;

   vg_manager_validate_framebuffer(ctx);

   if (vg_context_update_depth_stencil_rb(ctx, stfb->width, stfb->height))
      ctx->state.dirty |= DEPTH_STENCIL_DIRTY;

   /* blend state depends on fb format and paint color */
   if ((ctx->state.dirty & FRAMEBUFFER_DIRTY) ||
       (ctx->state.dirty & PAINT_DIRTY))
      ctx->state.dirty |= BLEND_DIRTY;

   renderer_validate(ctx->renderer, ctx->state.dirty,
         ctx->draw_buffer, &ctx->state.vg);

   ctx->state.dirty = 0;

   shader_set_masking(ctx->shader, ctx->state.vg.masking);
   shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode);
   shader_set_color_transform(ctx->shader, ctx->state.vg.color_transform);
}
void vg_validate_state(struct vg_context *ctx)
{
   vg_manager_validate_framebuffer(ctx);

   if ((ctx->state.dirty & BLEND_DIRTY)) {
      struct pipe_blend_state *blend = &ctx->state.g3d.blend;
      memset(blend, 0, sizeof(struct pipe_blend_state));
      blend->rt[0].blend_enable = 1;
      blend->rt[0].colormask = PIPE_MASK_RGBA;

      switch (ctx->state.vg.blend_mode) {
      case VG_BLEND_SRC:
         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
         blend->rt[0].blend_enable = 0;
         break;
      case VG_BLEND_SRC_OVER:
         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_SRC_ALPHA;
         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
         break;
      case VG_BLEND_DST_OVER:
         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_INV_DST_ALPHA;
         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA;
         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_DST_ALPHA;
         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA;
         break;
      case VG_BLEND_SRC_IN:
         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_DST_ALPHA;
         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA;
         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
         break;
      case VG_BLEND_DST_IN:
         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_ZERO;
         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_SRC_ALPHA;
         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
         break;
      case VG_BLEND_MULTIPLY:
      case VG_BLEND_SCREEN:
      case VG_BLEND_DARKEN:
      case VG_BLEND_LIGHTEN:
         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_ZERO;
         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
         blend->rt[0].blend_enable = 0;
         break;
      case VG_BLEND_ADDITIVE:
         blend->rt[0].rgb_src_factor   = PIPE_BLENDFACTOR_ONE;
         blend->rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
         blend->rt[0].rgb_dst_factor   = PIPE_BLENDFACTOR_ONE;
         blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
         break;
      default:
         assert(!"not implemented blend mode");
      }
      cso_set_blend(ctx->cso_context, &ctx->state.g3d.blend);
   }
   if ((ctx->state.dirty & RASTERIZER_DIRTY)) {
      struct pipe_rasterizer_state *raster = &ctx->state.g3d.rasterizer;
      memset(raster, 0, sizeof(struct pipe_rasterizer_state));
      raster->gl_rasterization_rules = 1;
      cso_set_rasterizer(ctx->cso_context, &ctx->state.g3d.rasterizer);
   }
   if ((ctx->state.dirty & VIEWPORT_DIRTY)) {
      struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb;
      const VGint param_bytes = 8 * sizeof(VGfloat);
      VGfloat vs_consts[8] = {
         2.f/fb->width, 2.f/fb->height, 1, 1,
         -1, -1, 0, 0
      };
      struct pipe_resource **cbuf = &ctx->vs_const_buffer;

      vg_set_viewport(ctx, VEGA_Y0_BOTTOM);

      pipe_resource_reference(cbuf, NULL);
      *cbuf = pipe_buffer_create(ctx->pipe->screen, 
				 PIPE_BIND_CONSTANT_BUFFER,
				 param_bytes);

      if (*cbuf) {
         st_no_flush_pipe_buffer_write(ctx, *cbuf,
                                       0, param_bytes, vs_consts);
      }
      ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_VERTEX, 0, *cbuf);
   }
   if ((ctx->state.dirty & VS_DIRTY)) {
      cso_set_vertex_shader_handle(ctx->cso_context,
                                   vg_plain_vs(ctx));
   }

   /* must be last because it renders to the depth buffer*/
   if ((ctx->state.dirty & DEPTH_STENCIL_DIRTY)) {
      update_clip_state(ctx);
      cso_set_depth_stencil_alpha(ctx->cso_context, &ctx->state.g3d.dsa);
   }

   shader_set_masking(ctx->shader, ctx->state.vg.masking);
   shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode);

   ctx->state.dirty = NONE_DIRTY;
}