st/vega: Add POLYGON_STENCIL and POLYGON_FILL renderer state.

The states are designated for polygon filling.  Polygon filling is a
two-pass process utilizing the stencil buffer.  polygon_fill and
polygon_array_fill functions are updated to make use of the state.
This commit is contained in:
Chia-I Wu 2010-11-27 15:04:30 +08:00
parent b23f732075
commit 3b71cb6ad6
3 changed files with 270 additions and 233 deletions

View file

@ -244,24 +244,11 @@ VGboolean polygon_is_closed(struct polygon *p)
return floatsEqual(start[0], end[0]) && floatsEqual(start[1], end[1]);
}
static void set_blend_for_fill(struct pipe_blend_state *blend)
{
memset(blend, 0, sizeof(struct pipe_blend_state));
blend->rt[0].colormask = 0; /*disable colorwrites*/
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_INV_SRC_ALPHA;
blend->rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
}
static void draw_polygon(struct vg_context *ctx,
struct polygon *poly)
static void polygon_prepare_buffer(struct vg_context *ctx,
struct polygon *poly)
{
int vert_size;
struct pipe_context *pipe;
struct pipe_vertex_buffer vbuffer;
struct pipe_vertex_element velement;
vert_size = poly->num_verts * COMPONENTS * sizeof(float);
@ -281,35 +268,15 @@ static void draw_polygon(struct vg_context *ctx,
PIPE_BIND_VERTEX_BUFFER);
poly->dirty = VG_FALSE;
}
/* tell pipe about the vertex buffer */
memset(&vbuffer, 0, sizeof(vbuffer));
vbuffer.buffer = poly->vbuf;
vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */
vbuffer.buffer_offset = 0;
vbuffer.max_index = poly->num_verts - 1;
pipe->set_vertex_buffers(pipe, 1, &vbuffer);
/* tell pipe about the vertex attributes */
memset(&velement, 0, sizeof(velement));
velement.src_offset = 0;
velement.instance_divisor = 0;
velement.vertex_buffer_index = 0;
velement.src_format = PIPE_FORMAT_R32G32_FLOAT;
cso_set_vertex_elements(ctx->cso_context, 1, &velement);
/* draw */
util_draw_arrays(pipe, PIPE_PRIM_TRIANGLE_FAN, 0, (uint) poly->num_verts);
}
void polygon_fill(struct polygon *poly, struct vg_context *ctx)
{
struct pipe_depth_stencil_alpha_state dsa;
struct pipe_stencil_ref sr;
struct pipe_blend_state blend;
struct pipe_vertex_element velement;
struct pipe_vertex_buffer vbuffer;
VGfloat bounds[4];
VGfloat min_x, min_y, max_x, max_y;
assert(poly);
polygon_bounding_rect(poly, bounds);
min_x = bounds[0];
@ -322,113 +289,42 @@ void polygon_fill(struct polygon *poly, struct vg_context *ctx)
min_x, min_y, max_x, max_y);
#endif
set_blend_for_fill(&blend);
polygon_prepare_buffer(ctx, poly);
memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
memset(&sr, 0, sizeof(struct pipe_stencil_ref));
/* only need a fixed 0. Rely on default or move it out at least? */
cso_set_stencil_ref(ctx->cso_context, &sr);
/* tell renderer about the vertex attributes */
memset(&velement, 0, sizeof(velement));
velement.src_offset = 0;
velement.instance_divisor = 0;
velement.vertex_buffer_index = 0;
velement.src_format = PIPE_FORMAT_R32G32_FLOAT;
cso_save_blend(ctx->cso_context);
cso_save_depth_stencil_alpha(ctx->cso_context);
/* tell renderer about the vertex buffer */
memset(&vbuffer, 0, sizeof(vbuffer));
vbuffer.buffer = poly->vbuf;
vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */
vbuffer.buffer_offset = 0;
vbuffer.max_index = poly->num_verts - 1;
dsa.stencil[0].enabled = 1;
if (ctx->state.vg.fill_rule == VG_EVEN_ODD) {
dsa.stencil[0].writemask = 1;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT;
dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
dsa.stencil[0].valuemask = ~0;
renderer_polygon_stencil_begin(ctx->renderer,
&velement, ctx->state.vg.fill_rule, VG_FALSE);
renderer_polygon_stencil(ctx->renderer, &vbuffer,
PIPE_PRIM_TRIANGLE_FAN, 0, (VGuint) poly->num_verts);
renderer_polygon_stencil_end(ctx->renderer);
cso_set_blend(ctx->cso_context, &blend);
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
draw_polygon(ctx, poly);
} else if (ctx->state.vg.fill_rule == VG_NON_ZERO) {
struct pipe_screen *screen = ctx->pipe->screen;
if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) {
/* front */
dsa.stencil[0].writemask = ~0;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
dsa.stencil[0].valuemask = ~0;
/* back */
dsa.stencil[1].enabled = 1;
dsa.stencil[1].writemask = ~0;
dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
dsa.stencil[1].func = PIPE_FUNC_ALWAYS;
dsa.stencil[1].valuemask = ~0;
cso_set_blend(ctx->cso_context, &blend);
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
draw_polygon(ctx, poly);
} else {
struct pipe_rasterizer_state raster;
memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state));
cso_save_rasterizer(ctx->cso_context);
dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
dsa.stencil[0].valuemask = ~0;
raster.cull_face = PIPE_FACE_BACK;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
cso_set_blend(ctx->cso_context, &blend);
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
cso_set_rasterizer(ctx->cso_context, &raster);
draw_polygon(ctx, poly);
raster.cull_face = PIPE_FACE_FRONT;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
cso_set_rasterizer(ctx->cso_context, &raster);
draw_polygon(ctx, poly);
cso_restore_rasterizer(ctx->cso_context);
}
}
/* restore color writes */
cso_restore_blend(ctx->cso_context);
/* setup stencil ops */
dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
dsa.stencil[0].valuemask = dsa.stencil[0].writemask;
dsa.stencil[1].enabled = 0;
memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth,
sizeof(struct pipe_depth_state));
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
/* render the quad to propagate the rendering from stencil */
renderer_draw_quad(ctx->renderer, min_x, min_y,
max_x, max_y, 0.0f/*depth should be disabled*/);
cso_restore_depth_stencil_alpha(ctx->cso_context);
renderer_polygon_fill_begin(ctx->renderer, VG_FALSE);
renderer_polygon_fill(ctx->renderer, min_x, min_y, max_x, max_y);
renderer_polygon_fill_end(ctx->renderer);
}
void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx)
{
struct array *polys = polyarray->array;
struct pipe_depth_stencil_alpha_state dsa;
struct pipe_stencil_ref sr;
struct pipe_blend_state blend;
VGfloat min_x = polyarray->min_x;
VGfloat min_y = polyarray->min_y;
VGfloat max_x = polyarray->max_x;
VGfloat max_y = polyarray->max_y;
struct pipe_vertex_element velement;
struct pipe_vertex_buffer vbuffer;
VGint i;
@ -438,111 +334,35 @@ void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx)
min_x, min_y, max_x, max_y);
#endif
set_blend_for_fill(&blend);
/* tell renderer about the vertex attributes */
memset(&velement, 0, sizeof(velement));
velement.src_offset = 0;
velement.instance_divisor = 0;
velement.vertex_buffer_index = 0;
velement.src_format = PIPE_FORMAT_R32G32_FLOAT;
memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
memset(&sr, 0, sizeof(struct pipe_stencil_ref));
/* only need a fixed 0. Rely on default or move it out at least? */
cso_set_stencil_ref(ctx->cso_context, &sr);
/* tell renderer about the vertex buffer */
memset(&vbuffer, 0, sizeof(vbuffer));
vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */
vbuffer.buffer_offset = 0;
cso_save_blend(ctx->cso_context);
cso_save_depth_stencil_alpha(ctx->cso_context);
/* prepare the stencil buffer */
renderer_polygon_stencil_begin(ctx->renderer,
&velement, ctx->state.vg.fill_rule, VG_FALSE);
for (i = 0; i < polys->num_elements; ++i) {
struct polygon *poly = (((struct polygon**)polys->data)[i]);
dsa.stencil[0].enabled = 1;
if (ctx->state.vg.fill_rule == VG_EVEN_ODD) {
dsa.stencil[0].writemask = 1;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT;
dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
dsa.stencil[0].valuemask = ~0;
polygon_prepare_buffer(ctx, poly);
vbuffer.buffer = poly->vbuf;
vbuffer.max_index = poly->num_verts - 1;
cso_set_blend(ctx->cso_context, &blend);
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
for (i = 0; i < polys->num_elements; ++i) {
struct polygon *poly = (((struct polygon**)polys->data)[i]);
draw_polygon(ctx, poly);
}
} else if (ctx->state.vg.fill_rule == VG_NON_ZERO) {
struct pipe_screen *screen = ctx->pipe->screen;
if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) {
/* front */
dsa.stencil[0].writemask = ~0;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
dsa.stencil[0].valuemask = ~0;
/* back */
dsa.stencil[1].enabled = 1;
dsa.stencil[1].writemask = ~0;
dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
dsa.stencil[1].func = PIPE_FUNC_ALWAYS;
dsa.stencil[1].valuemask = ~0;
cso_set_blend(ctx->cso_context, &blend);
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
for (i = 0; i < polys->num_elements; ++i) {
struct polygon *poly = (((struct polygon**)polys->data)[i]);
draw_polygon(ctx, poly);
}
} else {
struct pipe_rasterizer_state raster;
memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state));
cso_save_rasterizer(ctx->cso_context);
dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
dsa.stencil[0].valuemask = ~0;
raster.cull_face = PIPE_FACE_BACK;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
cso_set_blend(ctx->cso_context, &blend);
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
cso_set_rasterizer(ctx->cso_context, &raster);
for (i = 0; i < polys->num_elements; ++i) {
struct polygon *poly = (((struct polygon**)polys->data)[i]);
draw_polygon(ctx, poly);
}
raster.cull_face = PIPE_FACE_FRONT;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
cso_set_rasterizer(ctx->cso_context, &raster);
for (i = 0; i < polys->num_elements; ++i) {
struct polygon *poly = (((struct polygon**)polys->data)[i]);
draw_polygon(ctx, poly);
}
cso_restore_rasterizer(ctx->cso_context);
}
renderer_polygon_stencil(ctx->renderer, &vbuffer,
PIPE_PRIM_TRIANGLE_FAN, 0, (VGuint) poly->num_verts);
}
renderer_polygon_stencil_end(ctx->renderer);
/* restore color writes */
cso_restore_blend(ctx->cso_context);
/* setup stencil ops */
dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
dsa.stencil[0].valuemask = dsa.stencil[0].writemask;
dsa.stencil[1].enabled = 0;
memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth,
sizeof(struct pipe_depth_state));
cso_set_depth_stencil_alpha(ctx->cso_context, &dsa);
/* render the quad to propagate the rendering from stencil */
renderer_draw_quad(ctx->renderer, min_x, min_y,
max_x, max_y, 0.0f/*depth should be disabled*/);
cso_restore_depth_stencil_alpha(ctx->cso_context);
/* fill it */
renderer_polygon_fill_begin(ctx->renderer, VG_FALSE);
renderer_polygon_fill(ctx->renderer, min_x, min_y, max_x, max_y);
renderer_polygon_fill_end(ctx->renderer);
}

View file

@ -51,6 +51,8 @@ typedef enum {
RENDERER_STATE_SCISSOR,
RENDERER_STATE_CLEAR,
RENDERER_STATE_FILTER,
RENDERER_STATE_POLYGON_STENCIL,
RENDERER_STATE_POLYGON_FILL,
NUM_RENDERER_STATES
} RendererState;
@ -103,6 +105,12 @@ struct renderer {
VGboolean use_sampler;
VGint tex_width, tex_height;
} filter;
struct {
struct pipe_depth_stencil_alpha_state dsa;
VGboolean manual_two_sides;
VGboolean restore_dsa;
} polygon_stencil;
} u;
};
@ -837,6 +845,193 @@ void renderer_filter_end(struct renderer *renderer)
renderer->state = RENDERER_STATE_INIT;
}
/**
* Prepare the renderer for polygon silhouette rendering.
*/
VGboolean renderer_polygon_stencil_begin(struct renderer *renderer,
struct pipe_vertex_element *velem,
VGFillRule rule,
VGboolean restore_dsa)
{
struct pipe_depth_stencil_alpha_state *dsa;
VGboolean manual_two_sides;
assert(renderer->state == RENDERER_STATE_INIT);
cso_save_blend(renderer->cso);
cso_save_depth_stencil_alpha(renderer->cso);
cso_set_vertex_elements(renderer->cso, 1, velem);
/* disable color writes */
renderer_set_blend(renderer, 0);
manual_two_sides = VG_FALSE;
dsa = &renderer->u.polygon_stencil.dsa;
memset(dsa, 0, sizeof(*dsa));
if (rule == VG_EVEN_ODD) {
dsa->stencil[0].enabled = 1;
dsa->stencil[0].writemask = 1;
dsa->stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa->stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa->stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT;
dsa->stencil[0].func = PIPE_FUNC_ALWAYS;
dsa->stencil[0].valuemask = ~0;
}
else {
assert(rule == VG_NON_ZERO);
/* front face */
dsa->stencil[0].enabled = 1;
dsa->stencil[0].writemask = ~0;
dsa->stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
dsa->stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
dsa->stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
dsa->stencil[0].func = PIPE_FUNC_ALWAYS;
dsa->stencil[0].valuemask = ~0;
if (renderer->pipe->screen->get_param(renderer->pipe->screen,
PIPE_CAP_TWO_SIDED_STENCIL)) {
/* back face */
dsa->stencil[1] = dsa->stencil[0];
dsa->stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
}
else {
manual_two_sides = VG_TRUE;
}
}
cso_set_depth_stencil_alpha(renderer->cso, dsa);
if (manual_two_sides)
cso_save_rasterizer(renderer->cso);
renderer->u.polygon_stencil.manual_two_sides = manual_two_sides;
renderer->u.polygon_stencil.restore_dsa = restore_dsa;
renderer->state = RENDERER_STATE_POLYGON_STENCIL;
return VG_TRUE;
}
/**
* Render a polygon silhouette to stencil buffer.
*/
void renderer_polygon_stencil(struct renderer *renderer,
struct pipe_vertex_buffer *vbuf,
VGuint mode, VGuint start, VGuint count)
{
assert(renderer->state == RENDERER_STATE_POLYGON_STENCIL);
renderer->pipe->set_vertex_buffers(renderer->pipe, 1, vbuf);
if (!renderer->u.polygon_stencil.manual_two_sides) {
util_draw_arrays(renderer->pipe, mode, start, count);
}
else {
struct pipe_rasterizer_state raster;
struct pipe_depth_stencil_alpha_state dsa;
/* TODO do not access owner state */
raster = renderer->owner->state.g3d.rasterizer;
dsa = renderer->u.polygon_stencil.dsa;
/* front */
raster.cull_face = PIPE_FACE_BACK;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
cso_set_rasterizer(renderer->cso, &raster);
cso_set_depth_stencil_alpha(renderer->cso, &dsa);
util_draw_arrays(renderer->pipe, mode, start, count);
/* back */
raster.cull_face = PIPE_FACE_FRONT;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
cso_set_rasterizer(renderer->cso, &raster);
cso_set_depth_stencil_alpha(renderer->cso, &dsa);
util_draw_arrays(renderer->pipe, mode, start, count);
}
}
/**
* End polygon silhouette rendering.
*/
void renderer_polygon_stencil_end(struct renderer *renderer)
{
assert(renderer->state == RENDERER_STATE_POLYGON_STENCIL);
if (renderer->u.polygon_stencil.manual_two_sides)
cso_restore_rasterizer(renderer->cso);
/* restore color writes */
cso_restore_blend(renderer->cso);
if (renderer->u.polygon_stencil.restore_dsa)
cso_restore_depth_stencil_alpha(renderer->cso);
renderer->state = RENDERER_STATE_INIT;
}
/**
* Prepare the renderer for polygon filling.
*/
VGboolean renderer_polygon_fill_begin(struct renderer *renderer,
VGboolean save_dsa)
{
struct pipe_depth_stencil_alpha_state dsa;
struct pipe_stencil_ref sr;
assert(renderer->state == RENDERER_STATE_INIT);
if (save_dsa)
cso_save_depth_stencil_alpha(renderer->cso);
/* only need a fixed 0. Rely on default or move it out at least? */
memset(&sr, 0, sizeof(sr));
cso_set_stencil_ref(renderer->cso, &sr);
/* setup stencil ops */
memset(&dsa, 0, sizeof(dsa));
dsa.stencil[0].enabled = 1;
dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL;
dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
dsa.stencil[0].valuemask = ~0;
dsa.stencil[0].writemask = ~0;
/* TODO do not access owner state */
dsa.depth = renderer->owner->state.g3d.dsa.depth;
cso_set_depth_stencil_alpha(renderer->cso, &dsa);
renderer->state = RENDERER_STATE_POLYGON_FILL;
return VG_TRUE;
}
/**
* Fill a polygon.
*/
void renderer_polygon_fill(struct renderer *renderer,
VGfloat min_x, VGfloat min_y,
VGfloat max_x, VGfloat max_y)
{
assert(renderer->state == RENDERER_STATE_POLYGON_FILL);
renderer_quad_pos(renderer, min_x, min_y, max_x, max_y, VG_TRUE);
renderer_quad_draw(renderer);
}
/**
* End polygon filling.
*/
void renderer_polygon_fill_end(struct renderer *renderer)
{
assert(renderer->state == RENDERER_STATE_POLYGON_FILL);
cso_restore_depth_stencil_alpha(renderer->cso);
renderer->state = RENDERER_STATE_INIT;
}
static void setup_shaders(struct renderer *ctx)
{
struct pipe_context *pipe = ctx->pipe;

View file

@ -37,6 +37,8 @@ struct pipe_resource;
struct pipe_sampler_state;
struct pipe_sampler_view;
struct pipe_surface;
struct pipe_vertex_element;
struct pipe_vertex_buffer;
struct renderer *renderer_create(struct vg_context *owner);
void renderer_destroy(struct renderer *);
@ -94,6 +96,26 @@ void renderer_filter(struct renderer *renderer,
void renderer_filter_end(struct renderer *renderer);
VGboolean renderer_polygon_stencil_begin(struct renderer *renderer,
struct pipe_vertex_element *velem,
VGFillRule rule,
VGboolean restore_dsa);
void renderer_polygon_stencil(struct renderer *renderer,
struct pipe_vertex_buffer *vbuf,
VGuint mode, VGuint start, VGuint count);
void renderer_polygon_stencil_end(struct renderer *renderer);
VGboolean renderer_polygon_fill_begin(struct renderer *renderer,
VGboolean save_dsa);
void renderer_polygon_fill(struct renderer *renderer,
VGfloat min_x, VGfloat min_y,
VGfloat max_x, VGfloat max_y);
void renderer_polygon_fill_end(struct renderer *renderer);
void renderer_draw_quad(struct renderer *,
VGfloat x1, VGfloat y1,
VGfloat x2, VGfloat y2,