st/vega: Fix pipe blend state for various blend modes.

rgb_src_factor and rgb_dst_factor should be PIPE_BLENDFACTOR_ONE for
VG_BLEND_SRC_IN and VG_BLEND_DST_IN respectively.  VG_BLEND_SRC_OVER can
be supported only when the fb has no alpha channel.  VG_BLEND_DST_OVER
and VG_BLEND_ADDITIVE have to be supported with a shader.

Note that Porter-Duff blending rules assume premultiplied alpha.
This commit is contained in:
Chia-I Wu
2010-12-04 21:42:51 +08:00
parent 0ee73edecc
commit 859106f196
3 changed files with 76 additions and 60 deletions
+65 -60
View File
@@ -42,6 +42,7 @@
#include "util/u_sampler.h"
#include "util/u_surface.h"
#include "util/u_math.h"
#include "util/u_format.h"
#include "cso_cache/cso_context.h"
#include "tgsi/tgsi_ureg.h"
@@ -1266,6 +1267,67 @@ static void update_clip_state(struct renderer *renderer,
}
}
static void renderer_validate_blend(struct renderer *renderer,
const struct vg_state *state,
enum pipe_format fb_format)
{
struct pipe_blend_state blend;
memset(&blend, 0, sizeof(blend));
blend.rt[0].colormask = PIPE_MASK_RGBA;
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;
/* TODO alpha masking happens after blending? */
switch (state->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;
break;
case VG_BLEND_SRC_OVER:
if (!util_format_has_alpha(fb_format)) {
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;
blend.rt[0].blend_enable = 1;
}
break;
case VG_BLEND_SRC_IN:
blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
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;
blend.rt[0].blend_enable = 1;
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_ONE;
blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
blend.rt[0].blend_enable = 1;
break;
case VG_BLEND_DST_OVER:
case VG_BLEND_MULTIPLY:
case VG_BLEND_SCREEN:
case VG_BLEND_DARKEN:
case VG_BLEND_LIGHTEN:
case VG_BLEND_ADDITIVE:
/* need a shader */
break;
default:
assert(!"not implemented blend mode");
break;
}
cso_set_blend(renderer->cso, &blend);
}
/**
* Propogate OpenVG state changes to the renderer. Only framebuffer, blending
* and scissoring states are relevant here.
@@ -1280,66 +1342,6 @@ void renderer_validate(struct renderer *renderer,
dirty |= renderer->dirty;
renderer->dirty = 0;
if (dirty & BLEND_DIRTY) {
struct pipe_blend_state blend;
memset(&blend, 0, sizeof(blend));
blend.rt[0].blend_enable = 1;
blend.rt[0].colormask = PIPE_MASK_RGBA;
switch (state->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(renderer->cso, &blend);
}
if (dirty & FRAMEBUFFER_DIRTY) {
struct pipe_framebuffer_state *fb = &renderer->g3d.fb;
struct matrix *proj = &renderer->projection;
@@ -1370,6 +1372,9 @@ void renderer_validate(struct renderer *renderer,
update_clip_state(renderer, state);
cso_set_depth_stencil_alpha(renderer->cso, &renderer->g3d.dsa);
}
if (dirty & BLEND_DIRTY)
renderer_validate_blend(renderer, state, stfb->strb->format);
}
/**
+7
View File
@@ -39,6 +39,7 @@
#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_math.h"
#include "util/u_format.h"
#define MAX_CONSTANTS 28
@@ -133,10 +134,16 @@ static VGboolean blend_use_shader(struct vg_context *ctx)
VGboolean advanced_blending;
switch (ctx->state.vg.blend_mode) {
case VG_BLEND_SRC_OVER:
advanced_blending =
util_format_has_alpha(ctx->draw_buffer->strb->format);
break;
case VG_BLEND_DST_OVER:
case VG_BLEND_MULTIPLY:
case VG_BLEND_SCREEN:
case VG_BLEND_DARKEN:
case VG_BLEND_LIGHTEN:
case VG_BLEND_ADDITIVE:
advanced_blending = VG_TRUE;
break;
default:
@@ -400,6 +400,10 @@ void vg_validate_state(struct vg_context *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 */
if (ctx->state.dirty & FRAMEBUFFER_DIRTY)
ctx->state.dirty |= BLEND_DIRTY;
renderer_validate(ctx->renderer, ctx->state.dirty,
ctx->draw_buffer, &ctx->state.vg);