st/vega: Add FILTER renderer state for image filtering.

The state is designated to perform image filtering.  execute_filter is
updated to make use of the state.
This commit is contained in:
Chia-I Wu 2010-11-26 23:25:18 +08:00
parent 6b241f532a
commit e5968a5355
3 changed files with 225 additions and 174 deletions

View file

@ -114,153 +114,11 @@ static INLINE struct pipe_sampler_view *create_texture_1d_view(struct vg_context
return view;
}
static INLINE struct pipe_surface * setup_framebuffer(struct vg_image *dst)
{
struct vg_context *ctx = vg_current_context();
struct pipe_context *pipe = ctx->pipe;
struct pipe_framebuffer_state fb;
struct pipe_surface *dst_surf = pipe->screen->get_tex_surface(
pipe->screen, dst->sampler_view->texture, 0, 0, 0,
PIPE_BIND_RENDER_TARGET);
/* drawing dest */
memset(&fb, 0, sizeof(fb));
fb.width = dst->x + dst_surf->width;
fb.height = dst->y + dst_surf->height;
fb.nr_cbufs = 1;
fb.cbufs[0] = dst_surf;
{
VGint i;
for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
fb.cbufs[i] = 0;
}
cso_set_framebuffer(ctx->cso_context, &fb);
return dst_surf;
}
static void setup_viewport(struct vg_image *dst)
{
struct vg_context *ctx = vg_current_context();
vg_set_viewport(ctx, VEGA_Y0_TOP);
}
static void setup_blend()
{
struct vg_context *ctx = vg_current_context();
struct pipe_blend_state blend;
memset(&blend, 0, sizeof(blend));
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;
if (ctx->state.vg.filter_channel_mask & VG_RED)
blend.rt[0].colormask |= PIPE_MASK_R;
if (ctx->state.vg.filter_channel_mask & VG_GREEN)
blend.rt[0].colormask |= PIPE_MASK_G;
if (ctx->state.vg.filter_channel_mask & VG_BLUE)
blend.rt[0].colormask |= PIPE_MASK_B;
if (ctx->state.vg.filter_channel_mask & VG_ALPHA)
blend.rt[0].colormask |= PIPE_MASK_A;
blend.rt[0].blend_enable = 0;
cso_set_blend(ctx->cso_context, &blend);
}
static void setup_constant_buffer(struct vg_context *ctx, const void *buffer,
VGint param_bytes)
{
struct pipe_context *pipe = ctx->pipe;
struct pipe_resource **cbuf = &ctx->filter.buffer;
/* We always need to get a new buffer, to keep the drivers simple and
* avoid gratuitous rendering synchronization. */
pipe_resource_reference(cbuf, NULL);
*cbuf = pipe_buffer_create(pipe->screen,
PIPE_BIND_CONSTANT_BUFFER,
param_bytes);
if (*cbuf) {
st_no_flush_pipe_buffer_write(ctx, *cbuf,
0, param_bytes, buffer);
}
ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, *cbuf);
}
static void setup_samplers(struct vg_context *ctx, struct filter_info *info)
{
struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
struct pipe_sampler_state sampler[3];
int num_samplers = 0;
int num_textures = 0;
samplers[0] = NULL;
samplers[1] = NULL;
samplers[2] = NULL;
samplers[3] = NULL;
sampler_views[0] = NULL;
sampler_views[1] = NULL;
sampler_views[2] = NULL;
sampler_views[3] = NULL;
memset(&sampler[0], 0, sizeof(struct pipe_sampler_state));
sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
sampler[0].wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
sampler[0].min_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
sampler[0].mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR;
sampler[0].normalized_coords = 1;
switch(info->tiling_mode) {
case VG_TILE_FILL:
sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
memcpy(sampler[0].border_color,
ctx->state.vg.tile_fill_color,
sizeof(VGfloat) * 4);
break;
case VG_TILE_PAD:
sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
break;
case VG_TILE_REPEAT:
sampler[0].wrap_s = PIPE_TEX_WRAP_REPEAT;
sampler[0].wrap_t = PIPE_TEX_WRAP_REPEAT;
break;
case VG_TILE_REFLECT:
sampler[0].wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT;
sampler[0].wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT;
break;
default:
debug_assert(!"Unknown tiling mode");
}
samplers[0] = &sampler[0];
sampler_views[0] = info->src->sampler_view;
++num_samplers;
++num_textures;
if (info->extra_texture_view) {
memcpy(&sampler[1], &sampler[0], sizeof(struct pipe_sampler_state));
samplers[1] = &sampler[1];
sampler_views[1] = info->extra_texture_view;
++num_samplers;
++num_textures;
}
cso_set_samplers(ctx->cso_context, num_samplers, (const struct pipe_sampler_state **)samplers);
cso_set_fragment_sampler_views(ctx->cso_context, num_textures, sampler_views);
}
static struct vg_shader * setup_color_matrix(struct vg_context *ctx, void *user_data)
{
struct vg_shader *shader =
shader_create_from_text(ctx->pipe, color_matrix_asm, 200,
PIPE_SHADER_FRAGMENT);
cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
return shader;
}
@ -275,7 +133,6 @@ static struct vg_shader * setup_convolution(struct vg_context *ctx, void *user_d
shader = shader_create_from_text(ctx->pipe, buffer, 200,
PIPE_SHADER_FRAGMENT);
cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
return shader;
}
@ -285,7 +142,6 @@ static struct vg_shader * setup_lookup(struct vg_context *ctx, void *user_data)
shader_create_from_text(ctx->pipe, lookup_asm,
200, PIPE_SHADER_FRAGMENT);
cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
return shader;
}
@ -316,49 +172,67 @@ static struct vg_shader * setup_lookup_single(struct vg_context *ctx, void *user
shader = shader_create_from_text(ctx->pipe, buffer, 200,
PIPE_SHADER_FRAGMENT);
cso_set_fragment_shader_handle(ctx->cso_context, shader->driver);
return shader;
}
static void execute_filter(struct vg_context *ctx,
struct filter_info *info)
{
struct pipe_surface *dst_surf;
struct vg_shader *shader;
const struct pipe_sampler_state *samplers[2];
struct pipe_sampler_view *views[2];
struct pipe_sampler_state sampler;
uint tex_wrap;
cso_save_framebuffer(ctx->cso_context);
cso_save_fragment_shader(ctx->cso_context);
cso_save_viewport(ctx->cso_context);
cso_save_blend(ctx->cso_context);
cso_save_samplers(ctx->cso_context);
cso_save_fragment_sampler_views(ctx->cso_context);
memset(&sampler, 0, sizeof(sampler));
sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
sampler.normalized_coords = 1;
switch (info->tiling_mode) {
case VG_TILE_FILL:
tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
/* copy border color */
memcpy(sampler.border_color, ctx->state.vg.tile_fill_color,
sizeof(sampler.border_color));
break;
case VG_TILE_PAD:
tex_wrap = PIPE_TEX_WRAP_CLAMP_TO_EDGE;;
break;
case VG_TILE_REPEAT:
tex_wrap = PIPE_TEX_WRAP_REPEAT;;
break;
case VG_TILE_REFLECT:
tex_wrap = PIPE_TEX_WRAP_MIRROR_REPEAT;
break;
default:
debug_assert(!"Unknown tiling mode");
break;
}
sampler.wrap_s = tex_wrap;
sampler.wrap_t = tex_wrap;
sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
samplers[0] = samplers[1] = &sampler;
views[0] = info->src->sampler_view;
views[1] = info->extra_texture_view;
dst_surf = setup_framebuffer(info->dst);
setup_viewport(info->dst);
setup_blend();
setup_constant_buffer(ctx, info->const_buffer, info->const_buffer_len);
shader = info->setup_shader(ctx, info->user_data);
setup_samplers(ctx, info);
renderer_draw_texture(ctx->renderer,
info->src->sampler_view->texture,
info->dst->x, info->dst->y,
info->dst->x + info->dst->width,
info->dst->y + info->dst->height,
info->dst->x, info->dst->y,
info->dst->x + info->dst->width,
info->dst->y + info->dst->height);
cso_restore_framebuffer(ctx->cso_context);
cso_restore_fragment_shader(ctx->cso_context);
cso_restore_viewport(ctx->cso_context);
cso_restore_blend(ctx->cso_context);
cso_restore_samplers(ctx->cso_context);
cso_restore_fragment_sampler_views(ctx->cso_context);
if (renderer_filter_begin(ctx->renderer,
info->dst->sampler_view->texture, VG_TRUE,
ctx->state.vg.filter_channel_mask,
samplers, views, (info->extra_texture_view) ? 2 : 1,
shader->driver, info->const_buffer, info->const_buffer_len)) {
renderer_filter(ctx->renderer,
info->dst->x, info->dst->y, info->dst->width, info->dst->height,
info->src->x, info->src->y, info->src->width, info->src->height);
renderer_filter_end(ctx->renderer);
}
vg_shader_destroy(ctx, shader);
pipe_surface_reference(&dst_surf, NULL);
}
void vegaColorMatrix(VGImage dst, VGImage src,

View file

@ -28,6 +28,7 @@
#include "renderer.h"
#include "vg_context.h"
#include "image.h"
#include "pipe/p_context.h"
#include "pipe/p_state.h"
@ -49,6 +50,7 @@ typedef enum {
RENDERER_STATE_DRAWTEX,
RENDERER_STATE_SCISSOR,
RENDERER_STATE_CLEAR,
RENDERER_STATE_FILTER,
NUM_RENDERER_STATES
} RendererState;
@ -96,6 +98,11 @@ struct renderer {
struct {
VGboolean restore_dsa;
} scissor;
struct {
VGboolean use_sampler;
VGint tex_width, tex_height;
} filter;
} u;
};
@ -320,6 +327,45 @@ static void renderer_set_samplers(struct renderer *r,
cso_set_fragment_sampler_views(r->cso, num_views, views);
}
/**
* Set custom renderer fragment shader, and optionally set samplers and views
* and upload the fragment constant buffer.
*
* This function modifies fragment_shader, samplers and fragment_sampler_views
* states.
*/
static void renderer_set_custom_fs(struct renderer *renderer,
void *fs,
const struct pipe_sampler_state **samplers,
struct pipe_sampler_view **views,
VGint num_samplers,
const void *const_buffer,
VGint const_buffer_len)
{
cso_set_fragment_shader_handle(renderer->cso, fs);
/* set samplers and views */
if (num_samplers) {
cso_set_samplers(renderer->cso, num_samplers, samplers);
cso_set_fragment_sampler_views(renderer->cso, num_samplers, views);
}
/* upload fs constant buffer */
if (const_buffer_len) {
struct pipe_resource *cbuf;
cbuf = pipe_buffer_create(renderer->pipe->screen,
PIPE_BIND_CONSTANT_BUFFER, const_buffer_len);
pipe_buffer_write(renderer->pipe, cbuf, 0,
const_buffer_len, const_buffer);
renderer->pipe->set_constant_buffer(renderer->pipe,
PIPE_SHADER_FRAGMENT, 0, cbuf);
/* destroy cbuf automatically */
pipe_resource_reference(&cbuf, NULL);
}
}
/**
* Setup renderer quad position.
*/
@ -678,6 +724,119 @@ void renderer_clear_end(struct renderer *renderer)
renderer->state = RENDERER_STATE_INIT;
}
/**
* Prepare the renderer for image filtering.
*/
VGboolean renderer_filter_begin(struct renderer *renderer,
struct pipe_resource *dst,
VGboolean y0_top,
VGbitfield channel_mask,
const struct pipe_sampler_state **samplers,
struct pipe_sampler_view **views,
VGint num_samplers,
void *fs,
const void *const_buffer,
VGint const_buffer_len)
{
struct pipe_surface *surf;
assert(renderer->state == RENDERER_STATE_INIT);
if (!fs)
return VG_FALSE;
if (!renderer_can_support(renderer, dst, PIPE_BIND_RENDER_TARGET))
return VG_FALSE;
surf = renderer->pipe->screen->get_tex_surface(renderer->pipe->screen,
dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
if (!surf)
return VG_FALSE;
cso_save_framebuffer(renderer->cso);
cso_save_viewport(renderer->cso);
cso_save_blend(renderer->cso);
/* set the image as the target */
renderer_set_target(renderer, surf, NULL, y0_top);
pipe_surface_reference(&surf, NULL);
renderer_set_blend(renderer, channel_mask);
if (num_samplers) {
struct pipe_resource *tex;
cso_save_samplers(renderer->cso);
cso_save_fragment_sampler_views(renderer->cso);
cso_save_fragment_shader(renderer->cso);
cso_save_vertex_shader(renderer->cso);
renderer_set_custom_fs(renderer, fs,
samplers, views, num_samplers,
const_buffer, const_buffer_len);
renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
tex = views[0]->texture;
renderer->u.filter.tex_width = tex->width0;
renderer->u.filter.tex_height = tex->height0;
renderer->u.filter.use_sampler = VG_TRUE;
}
else {
cso_save_fragment_shader(renderer->cso);
renderer_set_custom_fs(renderer, fs, NULL, NULL, 0,
const_buffer, const_buffer_len);
renderer->u.filter.use_sampler = VG_FALSE;
}
renderer->state = RENDERER_STATE_FILTER;
return VG_TRUE;
}
/**
* Draw into a rectangle of the destination with the specified region of the
* texture(s).
*
* The coordinates are in surface coordinates.
*/
void renderer_filter(struct renderer *renderer,
VGint x, VGint y, VGint w, VGint h,
VGint sx, VGint sy, VGint sw, VGint sh)
{
assert(renderer->state == RENDERER_STATE_FILTER);
renderer_quad_pos(renderer, x, y, x + w, y + h, VG_FALSE);
if (renderer->u.filter.use_sampler) {
renderer_quad_texcoord(renderer, sx, sy, sx + sw, sy + sh,
renderer->u.filter.tex_width,
renderer->u.filter.tex_height);
}
renderer_quad_draw(renderer);
}
/**
* End image filtering and restore the states.
*/
void renderer_filter_end(struct renderer *renderer)
{
assert(renderer->state == RENDERER_STATE_FILTER);
if (renderer->u.filter.use_sampler) {
cso_restore_samplers(renderer->cso);
cso_restore_fragment_sampler_views(renderer->cso);
cso_restore_vertex_shader(renderer->cso);
}
cso_restore_framebuffer(renderer->cso);
cso_restore_viewport(renderer->cso);
cso_restore_blend(renderer->cso);
cso_restore_fragment_shader(renderer->cso);
renderer->state = RENDERER_STATE_INIT;
}
static void setup_shaders(struct renderer *ctx)
{
struct pipe_context *pipe = ctx->pipe;

View file

@ -34,6 +34,7 @@ struct renderer;
struct vg_context;
struct pipe_resource;
struct pipe_sampler_state;
struct pipe_sampler_view;
struct pipe_surface;
@ -76,6 +77,23 @@ void renderer_clear(struct renderer *renderer,
void renderer_clear_end(struct renderer *renderer);
VGboolean renderer_filter_begin(struct renderer *renderer,
struct pipe_resource *dst,
VGboolean y0_top,
VGbitfield channel_mask,
const struct pipe_sampler_state **samplers,
struct pipe_sampler_view **views,
VGint num_samplers,
void *fs,
const void *const_buffer,
VGint const_buffer_len);
void renderer_filter(struct renderer *renderer,
VGint x, VGint y, VGint w, VGint h,
VGint sx, VGint sy, VGint sw, VGint sh);
void renderer_filter_end(struct renderer *renderer);
void renderer_draw_quad(struct renderer *,
VGfloat x1, VGfloat y1,
VGfloat x2, VGfloat y2,