static inline unsigned
svga_translate_blend_factor(const struct svga_context *svga, unsigned factor)
{
+ /* Note: there is no SVGA3D_BLENDOP_[INV]BLENDFACTORALPHA so
+ * we can't translate PIPE_BLENDFACTOR_[INV_]CONST_ALPHA properly.
+ */
switch (factor) {
case PIPE_BLENDFACTOR_ZERO: return SVGA3D_BLENDOP_ZERO;
case PIPE_BLENDFACTOR_SRC_ALPHA: return SVGA3D_BLENDOP_SRCALPHA;
}
+/**
+ * Translate gallium logicop mode to SVGA3D logicop mode.
+ */
+static int
+translate_logicop(enum pipe_logicop op)
+{
+ switch (op) {
+ case PIPE_LOGICOP_CLEAR:
+ return SVGA3D_DX11_LOGICOP_CLEAR;
+ case PIPE_LOGICOP_NOR:
+ return SVGA3D_DX11_LOGICOP_NOR;
+ case PIPE_LOGICOP_AND_INVERTED:
+ return SVGA3D_DX11_LOGICOP_AND_INVERTED;
+ case PIPE_LOGICOP_COPY_INVERTED:
+ return SVGA3D_DX11_LOGICOP_COPY_INVERTED;
+ case PIPE_LOGICOP_AND_REVERSE:
+ return SVGA3D_DX11_LOGICOP_AND_REVERSE;
+ case PIPE_LOGICOP_INVERT:
+ return SVGA3D_DX11_LOGICOP_INVERT;
+ case PIPE_LOGICOP_XOR:
+ return SVGA3D_DX11_LOGICOP_XOR;
+ case PIPE_LOGICOP_NAND:
+ return SVGA3D_DX11_LOGICOP_NAND;
+ case PIPE_LOGICOP_AND:
+ return SVGA3D_DX11_LOGICOP_AND;
+ case PIPE_LOGICOP_EQUIV:
+ return SVGA3D_DX11_LOGICOP_EQUIV;
+ case PIPE_LOGICOP_NOOP:
+ return SVGA3D_DX11_LOGICOP_NOOP;
+ case PIPE_LOGICOP_OR_INVERTED:
+ return SVGA3D_DX11_LOGICOP_OR_INVERTED;
+ case PIPE_LOGICOP_COPY:
+ return SVGA3D_DX11_LOGICOP_COPY;
+ case PIPE_LOGICOP_OR_REVERSE:
+ return SVGA3D_DX11_LOGICOP_OR_REVERSE;
+ case PIPE_LOGICOP_OR:
+ return SVGA3D_DX11_LOGICOP_OR;
+ case PIPE_LOGICOP_SET:
+ return SVGA3D_DX11_LOGICOP_SET;
+ default:
+ return SVGA3D_DX11_LOGICOP_COPY;
+ }
+};
+
+
/**
* Define a vgpu10 blend state object for the given
* svga blend state.
struct svga_blend_state *bs)
{
SVGA3dDXBlendStatePerRT perRT[SVGA3D_MAX_RENDER_TARGETS];
- unsigned try;
int i;
assert(svga_have_vgpu10(svga));
perRT[i].destBlendAlpha = bs->rt[i].dstblend_alpha;
perRT[i].blendOpAlpha = bs->rt[i].blendeq_alpha;
perRT[i].renderTargetWriteMask = bs->rt[i].writemask;
- perRT[i].logicOpEnable = 0;
- perRT[i].logicOp = SVGA3D_LOGICOP_COPY;
- assert(perRT[i].srcBlend == perRT[0].srcBlend);
+ perRT[i].logicOpEnable = bs->logicop_enabled;
+ perRT[i].logicOp = bs->logicop_mode;
}
- /* Loop in case command buffer is full and we need to flush and retry */
- for (try = 0; try < 2; try++) {
- enum pipe_error ret;
-
- ret = SVGA3D_vgpu10_DefineBlendState(svga->swc,
- bs->id,
- bs->alpha_to_coverage,
- bs->independent_blend_enable,
- perRT);
- if (ret == PIPE_OK)
- return;
- svga_context_flush(svga, NULL);
+ SVGA_RETRY(svga, SVGA3D_vgpu10_DefineBlendState(svga->swc,
+ bs->id,
+ bs->alpha_to_coverage,
+ bs->independent_blend_enable,
+ perRT));
+}
+
+
+/**
+ * If SVGA3D_DEVCAP_LOGIC_BLENDOPS is false, we can't directly implement
+ * GL's logicops. But we can emulate some of them. We set up the blending
+ * state for that here.
+ */
+static void
+emulate_logicop(struct svga_context *svga,
+ unsigned logicop_func,
+ struct svga_blend_state *blend,
+ unsigned buffer)
+{
+ switch (logicop_func) {
+ case PIPE_LOGICOP_XOR:
+ case PIPE_LOGICOP_INVERT:
+ blend->need_white_fragments = TRUE;
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_SUBTRACT;
+ break;
+ case PIPE_LOGICOP_CLEAR:
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_MINIMUM;
+ break;
+ case PIPE_LOGICOP_COPY:
+ blend->rt[buffer].blend_enable = FALSE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_ADD;
+ break;
+ case PIPE_LOGICOP_COPY_INVERTED:
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_ADD;
+ break;
+ case PIPE_LOGICOP_NOOP:
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_ADD;
+ break;
+ case PIPE_LOGICOP_SET:
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
+ break;
+ case PIPE_LOGICOP_AND:
+ /* Approximate with minimum - works for the 0 & anything case: */
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_MINIMUM;
+ break;
+ case PIPE_LOGICOP_AND_REVERSE:
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_INVDESTCOLOR;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_MINIMUM;
+ break;
+ case PIPE_LOGICOP_AND_INVERTED:
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_MINIMUM;
+ break;
+ case PIPE_LOGICOP_OR:
+ /* Approximate with maximum - works for the 1 | anything case: */
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
+ break;
+ case PIPE_LOGICOP_OR_REVERSE:
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_INVDESTCOLOR;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
+ break;
+ case PIPE_LOGICOP_OR_INVERTED:
+ blend->rt[buffer].blend_enable = TRUE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
+ break;
+ case PIPE_LOGICOP_NAND:
+ case PIPE_LOGICOP_NOR:
+ case PIPE_LOGICOP_EQUIV:
+ /* Fill these in with plausible values */
+ blend->rt[buffer].blend_enable = FALSE;
+ blend->rt[buffer].srcblend = SVGA3D_BLENDOP_ONE;
+ blend->rt[buffer].dstblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[buffer].blendeq = SVGA3D_BLENDEQ_ADD;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ blend->rt[buffer].srcblend_alpha = blend->rt[buffer].srcblend;
+ blend->rt[buffer].dstblend_alpha = blend->rt[buffer].dstblend;
+ blend->rt[buffer].blendeq_alpha = blend->rt[buffer].blendeq;
+
+ if (logicop_func == PIPE_LOGICOP_XOR) {
+ pipe_debug_message(&svga->debug.callback, CONFORMANCE,
+ "XOR logicop mode has limited support");
+ }
+ else if (logicop_func != PIPE_LOGICOP_COPY) {
+ pipe_debug_message(&svga->debug.callback, CONFORMANCE,
+ "general logicops are not supported");
}
}
+
static void *
svga_create_blend_state(struct pipe_context *pipe,
const struct pipe_blend_state *templ)
{
struct svga_context *svga = svga_context(pipe);
+ struct svga_screen *ss = svga_screen(pipe->screen);
struct svga_blend_state *blend = CALLOC_STRUCT( svga_blend_state );
unsigned i;
if (!blend)
return NULL;
+ /* Find index of first target with blending enabled. If no blending is
+ * enabled at all, first_enabled will be zero.
+ */
+ unsigned first_enabled = 0;
+ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+ if (templ->rt[i].blend_enable) {
+ first_enabled = i;
+ break;
+ }
+ }
+
/* Fill in the per-rendertarget blend state. We currently only
* support independent blend enable and colormask per render target.
*/
* top of D3D9 API. Instead we try to simulate with various blend modes.
*/
if (templ->logicop_enable) {
- switch (templ->logicop_func) {
- case PIPE_LOGICOP_XOR:
- case PIPE_LOGICOP_INVERT:
- blend->need_white_fragments = TRUE;
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_ONE;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_ONE;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_SUBTRACT;
- break;
- case PIPE_LOGICOP_CLEAR:
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_ZERO;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_MINIMUM;
- break;
- case PIPE_LOGICOP_COPY:
- blend->rt[i].blend_enable = FALSE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_ONE;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD;
- break;
- case PIPE_LOGICOP_COPY_INVERTED:
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD;
- break;
- case PIPE_LOGICOP_NOOP:
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_ZERO;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD;
- break;
- case PIPE_LOGICOP_SET:
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_ONE;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_ONE;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
- break;
- case PIPE_LOGICOP_AND:
- /* Approximate with minimum - works for the 0 & anything case: */
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_MINIMUM;
- break;
- case PIPE_LOGICOP_AND_REVERSE:
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_INVDESTCOLOR;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_MINIMUM;
- break;
- case PIPE_LOGICOP_AND_INVERTED:
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_MINIMUM;
- break;
- case PIPE_LOGICOP_OR:
- /* Approximate with maximum - works for the 1 | anything case: */
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
- break;
- case PIPE_LOGICOP_OR_REVERSE:
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_SRCCOLOR;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_INVDESTCOLOR;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
- break;
- case PIPE_LOGICOP_OR_INVERTED:
- blend->rt[i].blend_enable = TRUE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_INVSRCCOLOR;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_DESTCOLOR;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_MAXIMUM;
- break;
- case PIPE_LOGICOP_NAND:
- case PIPE_LOGICOP_NOR:
- case PIPE_LOGICOP_EQUIV:
- /* Fill these in with plausible values */
- blend->rt[i].blend_enable = FALSE;
- blend->rt[i].srcblend = SVGA3D_BLENDOP_ONE;
- blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO;
- blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD;
- break;
- default:
- assert(0);
- break;
- }
- blend->rt[i].srcblend_alpha = blend->rt[i].srcblend;
- blend->rt[i].dstblend_alpha = blend->rt[i].dstblend;
- blend->rt[i].blendeq_alpha = blend->rt[i].blendeq;
-
- if (templ->logicop_func == PIPE_LOGICOP_XOR) {
- pipe_debug_message(&svga->debug.callback, CONFORMANCE,
- "XOR logicop mode has limited support");
+ if (ss->haveBlendLogicops) {
+ blend->logicop_enabled = TRUE;
+ blend->logicop_mode = translate_logicop(templ->logicop_func);
+ blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD;
+ blend->rt[i].blendeq_alpha = SVGA3D_BLENDEQ_ADD;
+ blend->rt[i].srcblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO;
+ blend->rt[i].srcblend_alpha = SVGA3D_BLENDOP_ZERO;
+ blend->rt[i].dstblend_alpha = SVGA3D_BLENDOP_ZERO;
}
- else if (templ->logicop_func != PIPE_LOGICOP_COPY) {
- pipe_debug_message(&svga->debug.callback, CONFORMANCE,
- "general logicops are not supported");
+ else {
+ emulate_logicop(svga, templ->logicop_func, blend, i);
}
}
else {
- /* Note: the vgpu10 device does not yet support independent
- * blend terms per render target. Target[0] always specifies the
- * blending terms.
+ /* Note: per-target blend terms are only supported for sm4_1
+ * device. For vgpu10 device, the blending terms must be identical
+ * for all targets (this is why we need the first_enabled index).
*/
- if (templ->independent_blend_enable || templ->rt[0].blend_enable) {
- /* always use the 0th target's blending terms for now */
+ const unsigned j =
+ svga_have_sm4_1(svga) && templ->independent_blend_enable
+ ? i : first_enabled;
+ if (templ->independent_blend_enable || templ->rt[j].blend_enable) {
blend->rt[i].srcblend =
- svga_translate_blend_factor(svga, templ->rt[0].rgb_src_factor);
+ svga_translate_blend_factor(svga, templ->rt[j].rgb_src_factor);
blend->rt[i].dstblend =
- svga_translate_blend_factor(svga, templ->rt[0].rgb_dst_factor);
+ svga_translate_blend_factor(svga, templ->rt[j].rgb_dst_factor);
blend->rt[i].blendeq =
- svga_translate_blend_func(templ->rt[0].rgb_func);
+ svga_translate_blend_func(templ->rt[j].rgb_func);
blend->rt[i].srcblend_alpha =
- svga_translate_blend_factor(svga, templ->rt[0].alpha_src_factor);
+ svga_translate_blend_factor(svga, templ->rt[j].alpha_src_factor);
blend->rt[i].dstblend_alpha =
- svga_translate_blend_factor(svga, templ->rt[0].alpha_dst_factor);
+ svga_translate_blend_factor(svga, templ->rt[j].alpha_dst_factor);
blend->rt[i].blendeq_alpha =
- svga_translate_blend_func(templ->rt[0].alpha_func);
+ svga_translate_blend_func(templ->rt[j].alpha_func);
if (blend->rt[i].srcblend_alpha != blend->rt[i].srcblend ||
blend->rt[i].dstblend_alpha != blend->rt[i].dstblend ||
blend->independent_blend_enable = templ->independent_blend_enable;
blend->alpha_to_coverage = templ->alpha_to_coverage;
+ blend->alpha_to_one = templ->alpha_to_one;
if (svga_have_vgpu10(svga)) {
define_blend_state_object(svga, blend);
}
- svga->hud.num_state_objects++;
+ svga->hud.num_blend_objects++;
+ SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
+ SVGA_STATS_COUNT_BLENDSTATE);
return blend;
}
struct svga_blend_state *bs =
(struct svga_blend_state *) blend;
- if (bs->id != SVGA3D_INVALID_ID) {
- enum pipe_error ret;
-
- ret = SVGA3D_vgpu10_DestroyBlendState(svga->swc, bs->id);
- if (ret != PIPE_OK) {
- svga_context_flush(svga, NULL);
- ret = SVGA3D_vgpu10_DestroyBlendState(svga->swc, bs->id);
- assert(ret == PIPE_OK);
- }
+ if (svga_have_vgpu10(svga) && bs->id != SVGA3D_INVALID_ID) {
+ SVGA_RETRY(svga, SVGA3D_vgpu10_DestroyBlendState(svga->swc, bs->id));
if (bs->id == svga->state.hw_draw.blend_id)
svga->state.hw_draw.blend_id = SVGA3D_INVALID_ID;
}
FREE(blend);
- svga->hud.num_state_objects--;
+ svga->hud.num_blend_objects--;
}
static void svga_set_blend_color( struct pipe_context *pipe,