static void vrend_hw_emit_rs(struct vrend_context *ctx)
{
   struct pipe_rasterizer_state *state = &ctx->sub->rs_state;
   int i;

   if (has_feature(feat_depth_clamp)) {
      if (state->depth_clip)
         glDisable(GL_DEPTH_CLAMP);
      else
         glEnable(GL_DEPTH_CLAMP);
   }

   if (vrend_state.use_gles) {
      /* guest send invalid glPointSize parameter */
      if (!state->point_size_per_vertex &&
          state->point_size != 1.0f &&
          state->point_size != 0.0f) {
         report_gles_warn(ctx, GLES_WARN_POINT_SIZE);
      }
   } else if (state->point_size_per_vertex) {
      glEnable(GL_PROGRAM_POINT_SIZE);
   } else {
      glDisable(GL_PROGRAM_POINT_SIZE);
      if (state->point_size) {
         glPointSize(state->point_size);
      }
   }

   /* line_width < 0 is invalid, the guest sometimes forgot to set it. */
   glLineWidth(state->line_width <= 0 ? 1.0f : state->line_width);

   if (state->rasterizer_discard != ctx->sub->hw_rs_state.rasterizer_discard) {
      ctx->sub->hw_rs_state.rasterizer_discard = state->rasterizer_discard;
      if (state->rasterizer_discard)
         glEnable(GL_RASTERIZER_DISCARD);
      else
         glDisable(GL_RASTERIZER_DISCARD);
   }

   if (vrend_state.use_gles == true) {
      if (translate_fill(state->fill_front) != GL_FILL) {
         report_gles_warn(ctx, GLES_WARN_POLYGON_MODE);
      }
      if (translate_fill(state->fill_back) != GL_FILL) {
         report_gles_warn(ctx, GLES_WARN_POLYGON_MODE);
      }
   } else if (vrend_state.use_core_profile == false) {
      glPolygonMode(GL_FRONT, translate_fill(state->fill_front));
      glPolygonMode(GL_BACK, translate_fill(state->fill_back));
   } else if (state->fill_front == state->fill_back) {
      glPolygonMode(GL_FRONT_AND_BACK, translate_fill(state->fill_front));
   } else
      report_core_warn(ctx, CORE_PROFILE_WARN_POLYGON_MODE);

   if (state->offset_tri) {
      glEnable(GL_POLYGON_OFFSET_FILL);
   } else {
      glDisable(GL_POLYGON_OFFSET_FILL);
   }

   if (vrend_state.use_gles) {
      if (state->offset_line) {
         report_gles_warn(ctx, GLES_WARN_OFFSET_LINE);
      }
   } else if (state->offset_line) {
      glEnable(GL_POLYGON_OFFSET_LINE);
   } else {
      glDisable(GL_POLYGON_OFFSET_LINE);
   }

   if (vrend_state.use_gles) {
      if (state->offset_point) {
         report_gles_warn(ctx, GLES_WARN_OFFSET_POINT);
      }
   } else if (state->offset_point) {
      glEnable(GL_POLYGON_OFFSET_POINT);
   } else {
      glDisable(GL_POLYGON_OFFSET_POINT);
   }


   if (state->flatshade != ctx->sub->hw_rs_state.flatshade) {
      ctx->sub->hw_rs_state.flatshade = state->flatshade;
      if (vrend_state.use_core_profile == false) {
         if (state->flatshade) {
            glShadeModel(GL_FLAT);
         } else {
            glShadeModel(GL_SMOOTH);
         }
      }
   }

   if (state->clip_halfz != ctx->sub->hw_rs_state.clip_halfz) {
       if (has_feature(feat_clip_control)) {
          /* We only need to handle clip_halfz here, the bottom_edge_rule is
           * already handled via Gallium */
          GLenum depthrule = state->clip_halfz ? GL_ZERO_TO_ONE : GL_NEGATIVE_ONE_TO_ONE;
          glClipControl(GL_LOWER_LEFT, depthrule);
          ctx->sub->hw_rs_state.clip_halfz = state->clip_halfz;
       } else {
          vrend_printf("No clip control supported\n");
       }
   }
   if (state->flatshade_first != ctx->sub->hw_rs_state.flatshade_first) {
      ctx->sub->hw_rs_state.flatshade_first = state->flatshade_first;
      if (vrend_state.use_gles) {
         if (state->flatshade_first) {
            report_gles_warn(ctx, GLES_WARN_FLATSHADE_FIRST);
         }
      } else if (state->flatshade_first) {
         glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT);
      } else {
         glProvokingVertexEXT(GL_LAST_VERTEX_CONVENTION_EXT);
      }
   }

   if (!vrend_state.use_gles && has_feature(feat_polygon_offset_clamp))
       glPolygonOffsetClampEXT(state->offset_scale, state->offset_units, state->offset_clamp);
   else
       glPolygonOffset(state->offset_scale, state->offset_units);

   if (vrend_state.use_core_profile == false) {
      if (state->poly_stipple_enable)
         glEnable(GL_POLYGON_STIPPLE);
      else
         glDisable(GL_POLYGON_STIPPLE);
   } else if (state->poly_stipple_enable) {
      if (!ctx->pstip_inited)
         vrend_init_pstipple_texture(ctx);
   }

   if (state->point_quad_rasterization) {
      if (vrend_state.use_core_profile == false &&
          vrend_state.use_gles == false) {
         glEnable(GL_POINT_SPRITE);
      }

      if (vrend_state.use_gles == false) {
         glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, state->sprite_coord_mode ? GL_UPPER_LEFT : GL_LOWER_LEFT);
      }
   } else {
      if (vrend_state.use_core_profile == false &&
          vrend_state.use_gles == false) {
         glDisable(GL_POINT_SPRITE);
      }
   }

   if (state->cull_face != PIPE_FACE_NONE) {
      switch (state->cull_face) {
      case PIPE_FACE_FRONT:
         glCullFace(GL_FRONT);
         break;
      case PIPE_FACE_BACK:
         glCullFace(GL_BACK);
         break;
      case PIPE_FACE_FRONT_AND_BACK:
         glCullFace(GL_FRONT_AND_BACK);
         break;
      default:
         vrend_printf( "unhandled cull-face: %x\n", state->cull_face);
      }
      glEnable(GL_CULL_FACE);
   } else
      glDisable(GL_CULL_FACE);

   /* two sided lighting handled in shader for core profile */
   if (vrend_state.use_core_profile == false) {
      if (state->light_twoside)
         glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);
      else
         glDisable(GL_VERTEX_PROGRAM_TWO_SIDE);
   }

   if (state->clip_plane_enable != ctx->sub->hw_rs_state.clip_plane_enable) {
      ctx->sub->hw_rs_state.clip_plane_enable = state->clip_plane_enable;
      for (i = 0; i < 8; i++) {
         if (state->clip_plane_enable & (1 << i))
            glEnable(GL_CLIP_PLANE0 + i);
         else
            glDisable(GL_CLIP_PLANE0 + i);
      }
   }
   if (vrend_state.use_core_profile == false) {
      glLineStipple(state->line_stipple_factor, state->line_stipple_pattern);
      if (state->line_stipple_enable)
         glEnable(GL_LINE_STIPPLE);
      else
         glDisable(GL_LINE_STIPPLE);
   } else if (state->line_stipple_enable) {
      if (vrend_state.use_gles)
         report_core_warn(ctx, GLES_WARN_STIPPLE);
      else
         report_core_warn(ctx, CORE_PROFILE_WARN_STIPPLE);
   }


   if (vrend_state.use_gles) {
      if (state->line_smooth) {
         report_gles_warn(ctx, GLES_WARN_LINE_SMOOTH);
      }
   } else if (state->line_smooth) {
      glEnable(GL_LINE_SMOOTH);
   } else {
      glDisable(GL_LINE_SMOOTH);
   }

   if (vrend_state.use_gles) {
      if (state->poly_smooth) {
         report_gles_warn(ctx, GLES_WARN_POLY_SMOOTH);
      }
   } else if (state->poly_smooth) {
      glEnable(GL_POLYGON_SMOOTH);
   } else {
      glDisable(GL_POLYGON_SMOOTH);
   }

   if (vrend_state.use_core_profile == false) {
      if (state->clamp_vertex_color)
         glClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_TRUE);
      else
         glClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE);

      if (state->clamp_fragment_color)
         glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_TRUE);
      else
         glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);
   } else {
      if (state->clamp_vertex_color || state->clamp_fragment_color)
         report_core_warn(ctx, CORE_PROFILE_WARN_CLAMP);
   }

   if (has_feature(feat_multisample)) {
      if (has_feature(feat_sample_mask)) {
	 if (state->multisample)
	    glEnable(GL_SAMPLE_MASK);
	 else
	    glDisable(GL_SAMPLE_MASK);
      }

      /* GLES doesn't have GL_MULTISAMPLE */
      if (!vrend_state.use_gles) {
         if (state->multisample)
            glEnable(GL_MULTISAMPLE);
         else
            glDisable(GL_MULTISAMPLE);
      }

      if (has_feature(feat_sample_shading)) {
         if (state->force_persample_interp)
            glEnable(GL_SAMPLE_SHADING);
         else
            glDisable(GL_SAMPLE_SHADING);
      }
   }

   if (state->scissor)
      glEnable(GL_SCISSOR_TEST);
   else
      glDisable(GL_SCISSOR_TEST);
   ctx->sub->hw_rs_state.scissor = state->scissor;

}