summaryrefslogtreecommitdiff
path: root/src/sna/gen2_render.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sna/gen2_render.c')
-rw-r--r--src/sna/gen2_render.c1237
1 files changed, 1237 insertions, 0 deletions
diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c
new file mode 100644
index 00000000..896f7308
--- /dev/null
+++ b/src/sna/gen2_render.c
@@ -0,0 +1,1237 @@
+/*
+ * Copyright © 2006,2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Wang Zhenyu <zhenyu.z.wang@intel.com>
+ * Eric Anholt <eric@anholt.net>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sna.h"
+#include "sna_reg.h"
+#include "sna_render.h"
+#include "sna_render_inline.h"
+
+#include "gen2_render.h"
+
+#if DEBUG_RENDER
+#undef DBG
+#define DBG(x) ErrorF x
+#else
+#define NDEBUG 1
+#endif
+
+#define OUT_BATCH(v) batch_emit(sna, v)
+#define OUT_BATCH_F(v) batch_emit_float(sna, v)
+#define OUT_VERTEX(v) batch_emit_float(sna, v)
+
+static const struct blendinfo {
+ Bool dst_alpha;
+ Bool src_alpha;
+ uint32_t src_blend;
+ uint32_t dst_blend;
+} gen2_blend_op[] = {
+ /* Clear */
+ {0, 0, BLENDFACTOR_ZERO, BLENDFACTOR_ZERO},
+ /* Src */
+ {0, 0, BLENDFACTOR_ONE, BLENDFACTOR_ZERO},
+ /* Dst */
+ {0, 0, BLENDFACTOR_ZERO, BLENDFACTOR_ONE},
+ /* Over */
+ {0, 1, BLENDFACTOR_ONE, BLENDFACTOR_INV_SRC_ALPHA},
+ /* OverReverse */
+ {1, 0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ONE},
+ /* In */
+ {1, 0, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_ZERO},
+ /* InReverse */
+ {0, 1, BLENDFACTOR_ZERO, BLENDFACTOR_SRC_ALPHA},
+ /* Out */
+ {1, 0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ZERO},
+ /* OutReverse */
+ {0, 1, BLENDFACTOR_ZERO, BLENDFACTOR_INV_SRC_ALPHA},
+ /* Atop */
+ {1, 1, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA},
+ /* AtopReverse */
+ {1, 1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_SRC_ALPHA},
+ /* Xor */
+ {1, 1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA},
+ /* Add */
+ {0, 0, BLENDFACTOR_ONE, BLENDFACTOR_ONE},
+};
+
+static const struct formatinfo {
+ int fmt;
+ uint32_t card_fmt;
+} i8xx_tex_formats[] = {
+ {PICT_a8, MAPSURF_8BIT | MT_8BIT_A8},
+ {PICT_a8r8g8b8, MAPSURF_32BIT | MT_32BIT_ARGB8888},
+ {PICT_a8b8g8r8, MAPSURF_32BIT | MT_32BIT_ABGR8888},
+ {PICT_r5g6b5, MAPSURF_16BIT | MT_16BIT_RGB565},
+ {PICT_a1r5g5b5, MAPSURF_16BIT | MT_16BIT_ARGB1555},
+ {PICT_a4r4g4b4, MAPSURF_16BIT | MT_16BIT_ARGB4444},
+}, i85x_tex_formats[] = {
+ {PICT_x8r8g8b8, MAPSURF_32BIT | MT_32BIT_XRGB8888},
+ {PICT_x8b8g8r8, MAPSURF_32BIT | MT_32BIT_XBGR8888},
+};
+
+static inline uint32_t
+gen2_buf_tiling(uint32_t tiling)
+{
+ uint32_t v = 0;
+ switch (tiling) {
+ case I915_TILING_Y: v |= BUF_3D_TILE_WALK_Y;
+ case I915_TILING_X: v |= BUF_3D_TILED_SURFACE;
+ case I915_TILING_NONE: break;
+ }
+ return v;
+}
+
+static uint32_t
+gen2_get_dst_format(uint32_t format)
+{
+#define BIAS DSTORG_HORT_BIAS(0x8) | DSTORG_VERT_BIAS(0x8)
+ switch (format) {
+ default:
+ assert(0);
+ case PICT_a8r8g8b8:
+ case PICT_x8r8g8b8:
+ return COLR_BUF_ARGB8888 | BIAS;
+ case PICT_r5g6b5:
+ return COLR_BUF_RGB565 | BIAS;
+ case PICT_a1r5g5b5:
+ case PICT_x1r5g5b5:
+ return COLR_BUF_ARGB1555 | BIAS;
+ case PICT_a8:
+ return COLR_BUF_8BIT | BIAS;
+ case PICT_a4r4g4b4:
+ case PICT_x4r4g4b4:
+ return COLR_BUF_ARGB4444 | BIAS;
+ }
+#undef BIAS
+}
+
+static Bool
+gen2_check_dst_format(uint32_t format)
+{
+ switch (format) {
+ case PICT_a8r8g8b8:
+ case PICT_x8r8g8b8:
+ case PICT_r5g6b5:
+ case PICT_a1r5g5b5:
+ case PICT_x1r5g5b5:
+ case PICT_a8:
+ case PICT_a4r4g4b4:
+ case PICT_x4r4g4b4:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static uint32_t
+gen2_get_card_format(struct sna *sna, uint32_t format)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(i8xx_tex_formats); i++) {
+ if (i8xx_tex_formats[i].fmt == format)
+ return i8xx_tex_formats[i].card_fmt;
+ }
+
+ if (!(IS_I830(sna) || IS_845G(sna))) {
+ for (i = 0; i < ARRAY_SIZE(i85x_tex_formats); i++) {
+ if (i85x_tex_formats[i].fmt == format)
+ return i85x_tex_formats[i].card_fmt;
+ }
+ }
+
+ assert(0);
+ return 0;
+}
+
+static Bool
+gen2_check_card_format(struct sna *sna, uint32_t format)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(i8xx_tex_formats); i++) {
+ if (i8xx_tex_formats[i].fmt == format)
+ return TRUE;
+ }
+
+ if (!(IS_I830(sna) || IS_845G(sna))) {
+ for (i = 0; i < ARRAY_SIZE(i85x_tex_formats); i++) {
+ if (i85x_tex_formats[i].fmt == format)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static uint32_t
+gen2_sampler_tiling_bits(uint32_t tiling)
+{
+ uint32_t bits = 0;
+ switch (tiling) {
+ default:
+ assert(0);
+ case I915_TILING_Y:
+ bits |= TM0S1_TILE_WALK;
+ case I915_TILING_X:
+ bits |= TM0S1_TILED_SURFACE;
+ case I915_TILING_NONE:
+ break;
+ }
+ return bits;
+}
+
+static Bool
+gen2_check_filter(PicturePtr picture)
+{
+ switch (picture->filter) {
+ case PictFilterNearest:
+ case PictFilterBilinear:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static Bool
+gen2_check_repeat(PicturePtr picture)
+{
+ if (!picture->repeat)
+ return TRUE;
+
+ switch (picture->repeatType) {
+ case RepeatNone:
+ case RepeatNormal:
+ case RepeatPad:
+ case RepeatReflect:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static void
+gen2_emit_texture(struct sna *sna,
+ const struct sna_composite_channel *channel,
+ int unit)
+{
+ uint32_t filter;
+ uint32_t wrap_mode;
+ uint32_t texcoordtype;
+
+ if (channel->is_affine)
+ texcoordtype = TEXCOORDTYPE_CARTESIAN;
+ else
+ texcoordtype = TEXCOORDTYPE_HOMOGENEOUS;
+
+ switch (channel->repeat) {
+ default:
+ assert(0);
+ case RepeatNone:
+ wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
+ break;
+ case RepeatNormal:
+ wrap_mode = TEXCOORDMODE_WRAP;
+ break;
+ case RepeatPad:
+ wrap_mode = TEXCOORDMODE_CLAMP;
+ break;
+ case RepeatReflect:
+ wrap_mode = TEXCOORDMODE_MIRROR;
+ break;
+ }
+
+ switch (channel->filter) {
+ default:
+ assert(0);
+ case PictFilterNearest:
+ filter = (FILTER_NEAREST << TM0S3_MAG_FILTER_SHIFT |
+ FILTER_NEAREST << TM0S3_MIN_FILTER_SHIFT);
+ break;
+ case PictFilterBilinear:
+ filter = (FILTER_LINEAR << TM0S3_MAG_FILTER_SHIFT |
+ FILTER_LINEAR << TM0S3_MIN_FILTER_SHIFT);
+ break;
+ }
+ filter |= MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT;
+
+ OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
+ LOAD_TEXTURE_MAP(unit) | 4);
+ OUT_BATCH(kgem_add_reloc(&sna->kgem, sna->kgem.nbatch,
+ channel->bo,
+ I915_GEM_DOMAIN_SAMPLER << 16,
+ 0));
+ OUT_BATCH(((channel->height - 1) << TM0S1_HEIGHT_SHIFT) |
+ ((channel->width - 1) << TM0S1_WIDTH_SHIFT) |
+ gen2_get_card_format(sna, channel->pict_format) |
+ gen2_sampler_tiling_bits(channel->bo->tiling));
+ OUT_BATCH((channel->bo->pitch / 4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D);
+ OUT_BATCH(filter);
+ OUT_BATCH(0); /* default color */
+ OUT_BATCH(_3DSTATE_MAP_COORD_SET_CMD | TEXCOORD_SET(unit) |
+ ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL |
+ texcoordtype |
+ ENABLE_ADDR_V_CNTL | TEXCOORD_ADDR_V_MODE(wrap_mode) |
+ ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(wrap_mode));
+ /* map texel stream */
+ OUT_BATCH(_3DSTATE_MAP_COORD_SETBIND_CMD);
+ if (unit == 0)
+ OUT_BATCH(TEXBIND_SET0(TEXCOORDSRC_VTXSET_0) |
+ TEXBIND_SET1(TEXCOORDSRC_KEEP) |
+ TEXBIND_SET2(TEXCOORDSRC_KEEP) |
+ TEXBIND_SET3(TEXCOORDSRC_KEEP));
+ else
+ OUT_BATCH(TEXBIND_SET0(TEXCOORDSRC_VTXSET_0) |
+ TEXBIND_SET1(TEXCOORDSRC_VTXSET_1) |
+ TEXBIND_SET2(TEXCOORDSRC_KEEP) |
+ TEXBIND_SET3(TEXCOORDSRC_KEEP));
+ OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
+ (unit << 16) |
+ DISABLE_TEX_STREAM_BUMP |
+ ENABLE_TEX_STREAM_COORD_SET |
+ TEX_STREAM_COORD_SET(unit) |
+ ENABLE_TEX_STREAM_MAP_IDX |
+ TEX_STREAM_MAP_IDX(unit));
+}
+
+static void
+gen2_get_blend_factors(const struct sna_composite_op *op,
+ uint32_t *c_out,
+ uint32_t *a_out)
+{
+ uint32_t cblend, ablend;
+
+ /* If component alpha is active in the mask and the blend operation
+ * uses the source alpha, then we know we don't need the source
+ * value (otherwise we would have hit a fallback earlier), so we
+ * provide the source alpha (src.A * mask.X) as output color.
+ * Conversely, if CA is set and we don't need the source alpha, then
+ * we produce the source value (src.X * mask.X) and the source alpha
+ * is unused.. Otherwise, we provide the non-CA source value
+ * (src.X * mask.A).
+ *
+ * The PICT_FORMAT_RGB(pict) == 0 fixups are not needed on 855+'s a8
+ * pictures, but we need to implement it for 830/845 and there's no
+ * harm done in leaving it in.
+ */
+ cblend =
+ TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_MODULE |
+ TB0C_OUTPUT_WRITE_CURRENT;
+ ablend =
+ TB0A_RESULT_SCALE_1X | TB0A_OP_MODULE |
+ TB0A_OUTPUT_WRITE_CURRENT;
+
+ /* Get the source picture's channels into TBx_ARG1 */
+ if ((op->has_component_alpha && gen2_blend_op[op->op].src_alpha) ||
+ op->dst.format == PICT_a8) {
+ /* Producing source alpha value, so the first set of channels
+ * is src.A instead of src.X. We also do this if the destination
+ * is a8, in which case src.G is what's written, and the other
+ * channels are ignored.
+ */
+ ablend |= TB0A_ARG1_SEL_TEXEL0;
+ cblend |= TB0C_ARG1_SEL_TEXEL0 | TB0C_ARG1_REPLICATE_ALPHA;
+ } else {
+ if (PICT_FORMAT_RGB(op->src.pict_format) != 0)
+ cblend |= TB0C_ARG1_SEL_TEXEL0;
+ else
+ cblend |= TB0C_ARG1_SEL_ONE | TB0C_ARG1_INVERT; /* 0.0 */
+ ablend |= TB0A_ARG1_SEL_TEXEL0;
+ }
+
+ if (op->mask.bo) {
+ cblend |= TB0C_ARG2_SEL_TEXEL1;
+ if (op->dst.format == PICT_a8 || op->has_component_alpha)
+ cblend |= TB0C_ARG2_REPLICATE_ALPHA;
+ ablend |= TB0A_ARG2_SEL_TEXEL1;
+ } else {
+ cblend |= TB0C_ARG2_SEL_ONE;
+ ablend |= TB0A_ARG2_SEL_ONE;
+ }
+
+ *c_out = cblend;
+ *a_out = ablend;
+}
+
+static uint32_t gen2_get_blend_cntl(int op,
+ Bool has_component_alpha,
+ uint32_t dst_format)
+{
+ uint32_t sblend, dblend;
+
+ sblend = gen2_blend_op[op].src_blend;
+ dblend = gen2_blend_op[op].dst_blend;
+
+ /* If there's no dst alpha channel, adjust the blend op so that
+ * we'll treat it as always 1.
+ */
+ if (PICT_FORMAT_A(dst_format) == 0 && gen2_blend_op[op].dst_alpha) {
+ if (sblend == BLENDFACTOR_DST_ALPHA)
+ sblend = BLENDFACTOR_ONE;
+ else if (sblend == BLENDFACTOR_INV_DST_ALPHA)
+ sblend = BLENDFACTOR_ZERO;
+ }
+
+ /* If the source alpha is being used, then we should only be in a case
+ * where the source blend factor is 0, and the source blend value is
+ * the mask channels multiplied by the source picture's alpha.
+ */
+ if (has_component_alpha && gen2_blend_op[op].src_alpha) {
+ if (dblend == BLENDFACTOR_SRC_ALPHA)
+ dblend = BLENDFACTOR_SRC_COLR;
+ else if (dblend == BLENDFACTOR_INV_SRC_ALPHA)
+ dblend = BLENDFACTOR_INV_SRC_COLR;
+ }
+
+ return (sblend << S8_SRC_BLEND_FACTOR_SHIFT |
+ dblend << S8_DST_BLEND_FACTOR_SHIFT);
+}
+
+static void gen2_emit_invariant(struct sna *sna)
+{
+ OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(0));
+ OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(1));
+ OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(2));
+ OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(3));
+
+ OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD);
+ OUT_BATCH(0);
+
+ OUT_BATCH(_3DSTATE_DFLT_SPEC_CMD);
+ OUT_BATCH(0);
+
+ OUT_BATCH(_3DSTATE_DFLT_Z_CMD);
+ OUT_BATCH(0);
+
+ OUT_BATCH(_3DSTATE_FOG_MODE_CMD);
+ OUT_BATCH(FOGFUNC_ENABLE |
+ FOG_LINEAR_CONST | FOGSRC_INDEX_Z | ENABLE_FOG_DENSITY);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+
+ OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
+ MAP_UNIT(0) |
+ DISABLE_TEX_STREAM_BUMP |
+ ENABLE_TEX_STREAM_COORD_SET |
+ TEX_STREAM_COORD_SET(0) |
+ ENABLE_TEX_STREAM_MAP_IDX |
+ TEX_STREAM_MAP_IDX(0));
+ OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
+ MAP_UNIT(1) |
+ DISABLE_TEX_STREAM_BUMP |
+ ENABLE_TEX_STREAM_COORD_SET |
+ TEX_STREAM_COORD_SET(1) |
+ ENABLE_TEX_STREAM_MAP_IDX |
+ TEX_STREAM_MAP_IDX(1));
+ OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
+ MAP_UNIT(2) |
+ DISABLE_TEX_STREAM_BUMP |
+ ENABLE_TEX_STREAM_COORD_SET |
+ TEX_STREAM_COORD_SET(2) |
+ ENABLE_TEX_STREAM_MAP_IDX |
+ TEX_STREAM_MAP_IDX(2));
+ OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
+ MAP_UNIT(3) |
+ DISABLE_TEX_STREAM_BUMP |
+ ENABLE_TEX_STREAM_COORD_SET |
+ TEX_STREAM_COORD_SET(3) |
+ ENABLE_TEX_STREAM_MAP_IDX |
+ TEX_STREAM_MAP_IDX(3));
+
+ OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM);
+ OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(0));
+ OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM);
+ OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(1));
+ OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM);
+ OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(2));
+ OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM);
+ OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(3));
+
+ OUT_BATCH(_3DSTATE_RASTER_RULES_CMD |
+ ENABLE_POINT_RASTER_RULE |
+ OGL_POINT_RASTER_RULE |
+ ENABLE_LINE_STRIP_PROVOKE_VRTX |
+ ENABLE_TRI_FAN_PROVOKE_VRTX |
+ ENABLE_TRI_STRIP_PROVOKE_VRTX |
+ LINE_STRIP_PROVOKE_VRTX(1) |
+ TRI_FAN_PROVOKE_VRTX(2) | TRI_STRIP_PROVOKE_VRTX(2));
+
+ OUT_BATCH(_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
+ OUT_BATCH(_3DSTATE_SCISSOR_RECT_0_CMD);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+
+ OUT_BATCH(_3DSTATE_VERTEX_TRANSFORM);
+ OUT_BATCH(DISABLE_VIEWPORT_TRANSFORM | DISABLE_PERSPECTIVE_DIVIDE);
+
+ OUT_BATCH(_3DSTATE_W_STATE_CMD);
+ OUT_BATCH(MAGIC_W_STATE_DWORD1);
+ OUT_BATCH_F(1.0);
+
+ OUT_BATCH(_3DSTATE_COLOR_FACTOR_CMD);
+ OUT_BATCH(0x80808080); /* .5 required in alpha for GL_DOT3_RGBA_EXT */
+
+ OUT_BATCH(_3DSTATE_MAP_COORD_SETBIND_CMD);
+ OUT_BATCH(TEXBIND_SET3(TEXCOORDSRC_VTXSET_3) |
+ TEXBIND_SET2(TEXCOORDSRC_VTXSET_2) |
+ TEXBIND_SET1(TEXCOORDSRC_VTXSET_1) |
+ TEXBIND_SET0(TEXCOORDSRC_VTXSET_0));
+
+ /* copy from mesa */
+ OUT_BATCH(_3DSTATE_INDPT_ALPHA_BLEND_CMD |
+ DISABLE_INDPT_ALPHA_BLEND |
+ ENABLE_ALPHA_BLENDFUNC | ABLENDFUNC_ADD);
+
+ OUT_BATCH(_3DSTATE_FOG_COLOR_CMD |
+ FOG_COLOR_RED(0) | FOG_COLOR_GREEN(0) | FOG_COLOR_BLUE(0));
+
+ OUT_BATCH(_3DSTATE_CONST_BLEND_COLOR_CMD);
+ OUT_BATCH(0);
+
+ OUT_BATCH(_3DSTATE_MODES_1_CMD |
+ ENABLE_COLR_BLND_FUNC |
+ BLENDFUNC_ADD |
+ ENABLE_SRC_BLND_FACTOR |
+ SRC_BLND_FACT(BLENDFACTOR_ONE) |
+ ENABLE_DST_BLND_FACTOR | DST_BLND_FACT(BLENDFACTOR_ZERO));
+ OUT_BATCH(_3DSTATE_MODES_2_CMD |
+ ENABLE_GLOBAL_DEPTH_BIAS |
+ GLOBAL_DEPTH_BIAS(0) |
+ ENABLE_ALPHA_TEST_FUNC |
+ ALPHA_TEST_FUNC(0) | /* always */
+ ALPHA_REF_VALUE(0));
+ OUT_BATCH(_3DSTATE_MODES_3_CMD |
+ ENABLE_DEPTH_TEST_FUNC |
+ DEPTH_TEST_FUNC(0x2) | /* COMPAREFUNC_LESS */
+ ENABLE_ALPHA_SHADE_MODE | ALPHA_SHADE_MODE(SHADE_MODE_LINEAR) |
+ ENABLE_FOG_SHADE_MODE | FOG_SHADE_MODE(SHADE_MODE_LINEAR) |
+ ENABLE_SPEC_SHADE_MODE | SPEC_SHADE_MODE(SHADE_MODE_LINEAR) |
+ ENABLE_COLOR_SHADE_MODE | COLOR_SHADE_MODE(SHADE_MODE_LINEAR) |
+ ENABLE_CULL_MODE | CULLMODE_NONE);
+
+ OUT_BATCH(_3DSTATE_MODES_4_CMD |
+ ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) |
+ ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff) |
+ ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff));
+
+ OUT_BATCH(_3DSTATE_STENCIL_TEST_CMD |
+ ENABLE_STENCIL_PARMS |
+ STENCIL_FAIL_OP(0) | /* STENCILOP_KEEP */
+ STENCIL_PASS_DEPTH_FAIL_OP(0) | /* STENCILOP_KEEP */
+ STENCIL_PASS_DEPTH_PASS_OP(0) | /* STENCILOP_KEEP */
+ ENABLE_STENCIL_TEST_FUNC | STENCIL_TEST_FUNC(0) | /* COMPAREFUNC_ALWAYS */
+ ENABLE_STENCIL_REF_VALUE | STENCIL_REF_VALUE(0));
+
+ OUT_BATCH(_3DSTATE_MODES_5_CMD |
+ FLUSH_TEXTURE_CACHE |
+ ENABLE_SPRITE_POINT_TEX | SPRITE_POINT_TEX_OFF |
+ ENABLE_FIXED_LINE_WIDTH | FIXED_LINE_WIDTH(0x2) | /* 1.0 */
+ ENABLE_FIXED_POINT_WIDTH | FIXED_POINT_WIDTH(1));
+
+ OUT_BATCH(_3DSTATE_ENABLES_1_CMD |
+ DISABLE_LOGIC_OP |
+ DISABLE_STENCIL_TEST |
+ DISABLE_DEPTH_BIAS |
+ DISABLE_SPEC_ADD |
+ DISABLE_FOG |
+ DISABLE_ALPHA_TEST |
+ ENABLE_COLOR_BLEND |
+ DISABLE_DEPTH_TEST);
+ OUT_BATCH(_3DSTATE_ENABLES_2_CMD |
+ DISABLE_STENCIL_WRITE |
+ ENABLE_TEX_CACHE |
+ DISABLE_DITHER |
+ ENABLE_COLOR_MASK |
+ ENABLE_COLOR_WRITE |
+ DISABLE_DEPTH_WRITE);
+
+ OUT_BATCH(_3DSTATE_STIPPLE);
+
+ /* Set default blend state */
+ OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
+ TEXPIPE_COLOR |
+ ENABLE_TEXOUTPUT_WRT_SEL | TEXOP_OUTPUT_CURRENT |
+ DISABLE_TEX_CNTRL_STAGE |
+ TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS |
+ TEXOP_LAST_STAGE | TEXBLENDOP_ARG1);
+ OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
+ TEXPIPE_ALPHA |
+ ENABLE_TEXOUTPUT_WRT_SEL | TEXOP_OUTPUT_CURRENT |
+ TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1);
+ OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
+ TEXPIPE_COLOR |
+ TEXBLEND_ARG1 |
+ TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE);
+ OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
+ TEXPIPE_ALPHA |
+ TEXBLEND_ARG1 |
+ TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE);
+
+ OUT_BATCH(_3DSTATE_AA_CMD |
+ AA_LINE_ECAAR_WIDTH_ENABLE |
+ AA_LINE_ECAAR_WIDTH_1_0 |
+ AA_LINE_REGION_WIDTH_ENABLE |
+ AA_LINE_REGION_WIDTH_1_0 | AA_LINE_DISABLE);
+
+ sna->render_state.gen2.need_invariant = FALSE;
+}
+
+static void
+gen2_get_batch(struct sna *sna,
+ const struct sna_composite_op *op)
+{
+ kgem_set_mode(&sna->kgem, KGEM_RENDER);
+
+ if (!kgem_check_batch(&sna->kgem, 50)) {
+ DBG(("%s: flushing batch: size %d > %d\n",
+ __FUNCTION__, 50,
+ sna->kgem.surface-sna->kgem.nbatch));
+ kgem_submit(&sna->kgem);
+ }
+
+ if (sna->kgem.nreloc + 3 > KGEM_RELOC_SIZE(&sna->kgem)) {
+ DBG(("%s: flushing batch: reloc %d >= %d\n",
+ __FUNCTION__,
+ sna->kgem.nreloc + 3,
+ (int)KGEM_RELOC_SIZE(&sna->kgem)));
+ kgem_submit(&sna->kgem);
+ }
+
+ if (sna->kgem.nexec + 3 > KGEM_EXEC_SIZE(&sna->kgem)) {
+ DBG(("%s: flushing batch: exec %d >= %d\n",
+ __FUNCTION__,
+ sna->kgem.nexec + 1,
+ (int)KGEM_EXEC_SIZE(&sna->kgem)));
+ kgem_submit(&sna->kgem);
+ }
+
+ if (sna->render_state.gen2.need_invariant)
+ gen2_emit_invariant(sna);
+}
+
+static void gen2_emit_composite_state(struct sna *sna,
+ const struct sna_composite_op *op)
+{
+ uint32_t texcoordfmt;
+ uint32_t cblend, ablend;
+
+ gen2_get_batch(sna, op);
+
+ OUT_BATCH(_3DSTATE_BUF_INFO_CMD);
+ OUT_BATCH(BUF_3D_ID_COLOR_BACK |
+ gen2_buf_tiling(op->dst.bo->tiling) |
+ BUF_3D_PITCH(op->dst.bo->pitch));
+ OUT_BATCH(kgem_add_reloc(&sna->kgem, sna->kgem.nbatch,
+ op->dst.bo,
+ I915_GEM_DOMAIN_RENDER << 16 |
+ I915_GEM_DOMAIN_RENDER,
+ 0));
+
+ OUT_BATCH(_3DSTATE_DST_BUF_VARS_CMD);
+ OUT_BATCH(gen2_get_dst_format(op->dst.format));
+
+ OUT_BATCH(_3DSTATE_DRAW_RECT_CMD);
+ OUT_BATCH(0);
+ OUT_BATCH(0); /* ymin, xmin */
+ OUT_BATCH(DRAW_YMAX(op->dst.height - 1) |
+ DRAW_XMAX(op->dst.width - 1));
+ OUT_BATCH(0); /* yorig, xorig */
+
+ OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+ I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
+ OUT_BATCH((1 + (op->mask.bo != NULL)) << 12);
+ OUT_BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
+ OUT_BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
+ gen2_get_blend_cntl(op->op,
+ op->has_component_alpha,
+ op->dst.format) |
+ S8_ENABLE_COLOR_BUFFER_WRITE);
+
+ OUT_BATCH(_3DSTATE_INDPT_ALPHA_BLEND_CMD | DISABLE_INDPT_ALPHA_BLEND);
+
+ gen2_get_blend_factors(op, &cblend, &ablend);
+ OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
+ LOAD_TEXTURE_BLEND_STAGE(0) | 1);
+ OUT_BATCH(cblend);
+ OUT_BATCH(ablend);
+
+ OUT_BATCH(_3DSTATE_ENABLES_1_CMD | DISABLE_LOGIC_OP |
+ DISABLE_STENCIL_TEST | DISABLE_DEPTH_BIAS |
+ DISABLE_SPEC_ADD | DISABLE_FOG | DISABLE_ALPHA_TEST |
+ ENABLE_COLOR_BLEND | DISABLE_DEPTH_TEST);
+ /* We have to explicitly say we don't want write disabled */
+ OUT_BATCH(_3DSTATE_ENABLES_2_CMD | ENABLE_COLOR_MASK |
+ DISABLE_STENCIL_WRITE | ENABLE_TEX_CACHE |
+ DISABLE_DITHER | ENABLE_COLOR_WRITE | DISABLE_DEPTH_WRITE);
+
+ texcoordfmt = 0;
+ if (op->src.is_affine)
+ texcoordfmt |= TEXCOORDFMT_2D << 0;
+ else
+ texcoordfmt |= TEXCOORDFMT_3D << 0;
+ if (op->mask.bo) {
+ if (op->mask.is_affine)
+ texcoordfmt |= TEXCOORDFMT_2D << 2;
+ else
+ texcoordfmt |= TEXCOORDFMT_3D << 2;
+ }
+ OUT_BATCH(_3DSTATE_VERTEX_FORMAT_2_CMD | texcoordfmt);
+
+ gen2_emit_texture(sna, &op->src, 0);
+ if (op->mask.bo)
+ gen2_emit_texture(sna, &op->mask, 1);
+}
+
+static inline void
+gen2_emit_composite_dstcoord(struct sna *sna, int dstX, int dstY)
+{
+ OUT_VERTEX(dstX);
+ OUT_VERTEX(dstY);
+}
+
+static void
+gen2_emit_composite_texcoord(struct sna *sna,
+ const struct sna_composite_channel *channel,
+ int16_t x, int16_t y)
+{
+ float s = 0, t = 0, w = 1;
+
+ x += channel->offset[0];
+ y += channel->offset[1];
+
+ if (channel->is_affine) {
+ sna_get_transformed_coordinates(x, y,
+ channel->transform,
+ &s, &t);
+ OUT_VERTEX(s * channel->scale[0]);
+ OUT_VERTEX(t * channel->scale[1]);
+ } else {
+ sna_get_transformed_coordinates_3d(x, y,
+ channel->transform,
+ &s, &t, &w);
+ OUT_VERTEX(s * channel->scale[0]);
+ OUT_VERTEX(t * channel->scale[1]);
+ OUT_VERTEX(w);
+ }
+}
+
+static void
+gen2_emit_composite_vertex(struct sna *sna,
+ const struct sna_composite_op *op,
+ int16_t srcX, int16_t srcY,
+ int16_t mskX, int16_t mskY,
+ int16_t dstX, int16_t dstY)
+{
+ gen2_emit_composite_dstcoord(sna, dstX, dstY);
+ gen2_emit_composite_texcoord(sna, &op->src, srcX, srcY);
+ gen2_emit_composite_texcoord(sna, &op->mask, mskX, mskY);
+}
+
+static void
+gen2_emit_composite_primitive(struct sna *sna,
+ const struct sna_composite_op *op,
+ int16_t srcX, int16_t srcY,
+ int16_t mskX, int16_t mskY,
+ int16_t dstX, int16_t dstY,
+ int16_t w, int16_t h)
+{
+ dstX += op->dst.x;
+ dstY += op->dst.y;
+
+ gen2_emit_composite_vertex(sna, op,
+ srcX + w, srcY + h,
+ mskX + w, mskY + h,
+ dstX + w, dstY + h);
+ gen2_emit_composite_vertex(sna, op,
+ srcX, srcY + h,
+ mskX, mskY + h,
+ dstX, dstY + h);
+ gen2_emit_composite_vertex(sna, op,
+ srcX, srcY,
+ mskX, mskY,
+ dstX, dstY);
+}
+
+static void gen2_magic_ca_pass(struct sna *sna,
+ const struct sna_composite_op *op)
+{
+ uint32_t ablend, cblend;
+
+ if (!op->need_magic_ca_pass)
+ return;
+
+ OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(8) | 2);
+ OUT_BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
+ gen2_get_blend_cntl(PictOpAdd,
+ op->has_component_alpha,
+ op->dst.format) |
+ S8_ENABLE_COLOR_BUFFER_WRITE);
+
+ gen2_get_blend_factors(op, &cblend, &ablend);
+ OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
+ LOAD_TEXTURE_BLEND_STAGE(0) | 1);
+ OUT_BATCH(cblend);
+ OUT_BATCH(ablend);
+
+ memcpy(sna->kgem.batch + sna->kgem.nbatch,
+ sna->kgem.batch + sna->render_state.gen2.vertex_offset,
+ (1 + 3*sna->render.vertex_index)*sizeof(uint32_t));
+ sna->kgem.nbatch += 1 + 3*sna->render.vertex_index;
+}
+
+static void gen2_vertex_flush(struct sna *sna)
+{
+ if (sna->render.vertex_index == 0)
+ return;
+
+ sna->kgem.batch[sna->render_state.gen2.vertex_offset] |=
+ sna->render.vertex_index - 1;
+
+ if (sna->render.op)
+ gen2_magic_ca_pass(sna, sna->render.op);
+
+ sna->render_state.gen2.vertex_offset = 0;
+ sna->render.vertex_index = 0;
+}
+
+inline static int gen2_get_rectangles(struct sna *sna,
+ const const struct sna_composite_op *op,
+ int want)
+{
+ struct gen2_render_state *state = &sna->render_state.gen2;
+ int rem = batch_space(sna), size, need;
+
+ need = 0;
+ size = 3*op->floats_per_vertex;
+ if (op->need_magic_ca_pass)
+ need += 5, size *= 2;
+
+ need += size;
+ if (state->vertex_offset == 0)
+ need += 2;
+
+ if (rem < need)
+ return 0;
+
+ if (state->vertex_offset == 0) {
+ state->vertex_offset = sna->kgem.nbatch;
+ OUT_BATCH(PRIM3D_INLINE | PRIM3D_RECTLIST);
+ rem--;
+ }
+
+ if (want * size > rem)
+ want = rem / size;
+
+ sna->render.vertex_index += 3*want;
+ return want;
+}
+
+fastcall static void
+gen2_render_composite_blt(struct sna *sna,
+ const struct sna_composite_op *op,
+ const struct sna_composite_rectangles *r)
+{
+ if (!gen2_get_rectangles(sna, op, 1)) {
+ gen2_emit_composite_state(sna, op);
+ gen2_get_rectangles(sna, op, 1);
+ }
+
+ gen2_emit_composite_primitive(sna, op,
+ r->src.x, r->src.y,
+ r->mask.x, r->mask.y,
+ r->dst.x, r->dst.y,
+ r->width, r->height);
+}
+
+static void
+gen2_render_composite_boxes(struct sna *sna,
+ const struct sna_composite_op *op,
+ const BoxRec *box, int nbox)
+{
+ do {
+ int nbox_this_time;
+
+ nbox_this_time = gen2_get_rectangles(sna, op, nbox);
+ if (nbox_this_time == 0) {
+ gen2_emit_composite_state(sna, op);
+ nbox_this_time = gen2_get_rectangles(sna, op, nbox);
+ }
+ nbox -= nbox_this_time;
+
+ do {
+ gen2_emit_composite_primitive(sna, op,
+ box->x1, box->y1,
+ box->x1, box->y1,
+ box->x1, box->y1,
+ box->x2 - box->x1,
+ box->y2 - box->y1);
+ box++;
+ } while (--nbox_this_time);
+ } while (nbox);
+}
+
+static void gen2_render_composite_done(struct sna *sna,
+ const struct sna_composite_op *op)
+{
+ gen2_vertex_flush(sna);
+ sna->render.op = NULL;
+ _kgem_set_mode(&sna->kgem, KGEM_RENDER);
+
+ sna_render_composite_redirect_done(sna, op);
+
+ if (op->src.bo)
+ kgem_bo_destroy(&sna->kgem, op->src.bo);
+ if (op->mask.bo)
+ kgem_bo_destroy(&sna->kgem, op->mask.bo);
+}
+
+static Bool
+gen2_composite_solid_init(struct sna *sna,
+ struct sna_composite_channel *channel,
+ uint32_t color)
+{
+ channel->filter = PictFilterNearest;
+ channel->repeat = RepeatNormal;
+ channel->is_affine = TRUE;
+ channel->is_solid = TRUE;
+ channel->transform = NULL;
+ channel->width = 1;
+ channel->height = 1;
+ channel->pict_format = PICT_a8r8g8b8;
+
+ channel->bo = sna_render_get_solid(sna, color);
+
+ channel->scale[0] = channel->scale[1] = 1;
+ channel->offset[0] = channel->offset[1] = 0;
+ return channel->bo != NULL;
+}
+
+static int
+gen2_composite_picture(struct sna *sna,
+ PicturePtr picture,
+ struct sna_composite_channel *channel,
+ int x, int y,
+ int w, int h,
+ int dst_x, int dst_y)
+{
+ PixmapPtr pixmap;
+ uint32_t color;
+ int16_t dx, dy;
+
+ DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n",
+ __FUNCTION__, x, y, w, h, dst_x, dst_y));
+
+ channel->is_solid = FALSE;
+ channel->card_format = -1;
+
+ if (sna_picture_is_solid(picture, &color))
+ return gen2_composite_solid_init(sna, channel, color);
+
+ if (picture->pDrawable == NULL)
+ return sna_render_picture_fixup(sna, picture, channel,
+ x, y, w, h, dst_x, dst_y);
+
+ if (!gen2_check_repeat(picture))
+ return sna_render_picture_fixup(sna, picture, channel,
+ x, y, w, h, dst_x, dst_y);
+
+ if (!gen2_check_filter(picture))
+ return sna_render_picture_fixup(sna, picture, channel,
+ x, y, w, h, dst_x, dst_y);
+
+ channel->repeat = picture->repeat ? picture->repeatType : RepeatNone;
+ channel->filter = picture->filter;
+
+ pixmap = get_drawable_pixmap(picture->pDrawable);
+ get_drawable_deltas(picture->pDrawable, pixmap, &dx, &dy);
+
+ x += dx + picture->pDrawable->x;
+ y += dy + picture->pDrawable->y;
+
+ channel->is_affine = sna_transform_is_affine(picture->transform);
+ if (sna_transform_is_integer_translation(picture->transform, &dx, &dy)) {
+ DBG(("%s: integer translation (%d, %d), removing\n",
+ __FUNCTION__, dx, dy));
+ x += dx;
+ y += dy;
+ channel->transform = NULL;
+ channel->filter = PictFilterNearest;
+ } else
+ channel->transform = picture->transform;
+
+ if (!gen2_check_card_format(sna, picture->format))
+ return sna_render_picture_convert(sna, picture, channel, pixmap,
+ x, y, w, h, dst_x, dst_y);
+
+ channel->pict_format = picture->format;
+ if (pixmap->drawable.width > 8192 || pixmap->drawable.height > 8192)
+ return sna_render_picture_extract(sna, picture, channel,
+ x, y, w, h, dst_x, dst_y);
+
+ return sna_render_pixmap_bo(sna, channel, pixmap,
+ x, y, w, h, dst_x, dst_y);
+}
+
+static Bool
+gen2_composite_set_target(struct sna *sna,
+ struct sna_composite_op *op,
+ PicturePtr dst)
+{
+ struct sna_pixmap *priv;
+
+ op->dst.pixmap = get_drawable_pixmap(dst->pDrawable);
+ op->dst.format = dst->format;
+ op->dst.width = op->dst.pixmap->drawable.width;
+ op->dst.height = op->dst.pixmap->drawable.height;
+
+ priv = sna_pixmap_force_to_gpu(op->dst.pixmap);
+ if (priv == NULL)
+ return FALSE;
+
+ op->dst.bo = priv->gpu_bo;
+ if (!priv->gpu_only)
+ op->damage = &priv->gpu_damage;
+
+ get_drawable_deltas(dst->pDrawable, op->dst.pixmap,
+ &op->dst.x, &op->dst.y);
+ return TRUE;
+}
+
+static Bool
+try_blt(struct sna *sna,
+ PicturePtr dst,
+ PicturePtr source,
+ int width, int height)
+{
+ uint32_t color;
+
+ if (sna->kgem.mode == KGEM_BLT) {
+ DBG(("%s: already performing BLT\n", __FUNCTION__));
+ return TRUE;
+ }
+
+ if (width > 2048 || height > 2048) {
+ DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
+ __FUNCTION__, width, height));
+ return TRUE;
+ }
+
+ /* If it is a solid, try to use the BLT paths */
+ if (sna_picture_is_solid(source, &color))
+ return TRUE;
+
+ if (!source->pDrawable)
+ return FALSE;
+
+ return is_cpu(source->pDrawable);
+}
+
+static Bool
+gen2_render_composite(struct sna *sna,
+ uint8_t op,
+ PicturePtr src,
+ PicturePtr mask,
+ PicturePtr dst,
+ int16_t src_x, int16_t src_y,
+ int16_t mask_x, int16_t mask_y,
+ int16_t dst_x, int16_t dst_y,
+ int16_t width, int16_t height,
+ struct sna_composite_op *tmp)
+{
+ DBG(("%s()\n", __FUNCTION__));
+
+ /* Try to use the BLT engine unless it implies a
+ * 3D -> 2D context switch.
+ */
+ if (mask == NULL &&
+ try_blt(sna, dst, src, width, height) &&
+ sna_blt_composite(sna,
+ op, src, dst,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height,
+ tmp))
+ return TRUE;
+
+ if (op >= ARRAY_SIZE(gen2_blend_op)) {
+ DBG(("%s: fallback due to unhandled blend op: %d\n",
+ __FUNCTION__, op));
+ return FALSE;
+ }
+
+ if (!gen2_check_dst_format(dst->format)) {
+ DBG(("%s: fallback due to unhandled dst format: %x\n",
+ __FUNCTION__, dst->format));
+ return FALSE;
+ }
+
+ if (need_tiling(sna, width, height))
+ return sna_tiling_composite(sna,
+ op, src, mask, dst,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height,
+ tmp);
+
+ memset(&tmp->u.gen2, 0, sizeof(tmp->u.gen2));
+
+ if (!gen2_composite_set_target(sna, tmp, dst)) {
+ DBG(("%s: unable to set render target\n",
+ __FUNCTION__));
+ return FALSE;
+ }
+
+ tmp->op = op;
+ if (tmp->dst.width > 2048 ||
+ tmp->dst.height > 2048 ||
+ tmp->dst.bo->pitch > 8192) {
+ if (!sna_render_composite_redirect(sna, tmp,
+ dst_x, dst_y, width, height))
+ return FALSE;
+ }
+
+ switch (gen2_composite_picture(sna, src, &tmp->src,
+ src_x, src_y,
+ width, height,
+ dst_x, dst_y)) {
+ case -1:
+ goto cleanup_dst;
+ case 0:
+ gen2_composite_solid_init(sna, &tmp->src, 0);
+ case 1:
+ break;
+ }
+
+ if (mask) {
+ switch (gen2_composite_picture(sna, mask, &tmp->mask,
+ mask_x, mask_y,
+ width, height,
+ dst_x, dst_y)) {
+ case -1:
+ goto cleanup_src;
+ case 0:
+ gen2_composite_solid_init(sna, &tmp->mask, 0);
+ case 1:
+ break;
+ }
+
+ if (mask->componentAlpha && PICT_FORMAT_RGB(mask->format)) {
+ /* Check if it's component alpha that relies on a source alpha
+ * and on the source value. We can only get one of those
+ * into the single source value that we get to blend with.
+ */
+ tmp->has_component_alpha = TRUE;
+ if (gen2_blend_op[op].src_alpha &&
+ (gen2_blend_op[op].src_blend != BLENDFACTOR_ZERO)) {
+ if (op != PictOpOver)
+ return FALSE;
+
+ tmp->need_magic_ca_pass = TRUE;
+ tmp->op = PictOpOutReverse;
+ }
+ }
+ }
+
+ tmp->blt = gen2_render_composite_blt;
+ tmp->boxes = gen2_render_composite_boxes;
+ tmp->done = gen2_render_composite_done;
+
+ if (!kgem_check_bo(&sna->kgem, tmp->dst.bo))
+ kgem_submit(&sna->kgem);
+ if (!kgem_check_bo(&sna->kgem, tmp->src.bo))
+ kgem_submit(&sna->kgem);
+ if (!kgem_check_bo(&sna->kgem, tmp->mask.bo))
+ kgem_submit(&sna->kgem);
+
+ if (kgem_bo_is_dirty(tmp->src.bo) || kgem_bo_is_dirty(tmp->mask.bo))
+ kgem_emit_flush(&sna->kgem);
+
+ gen2_emit_composite_state(sna, tmp);
+
+ sna->render.op = tmp;
+ return TRUE;
+
+cleanup_src:
+ if (tmp->src.bo)
+ kgem_bo_destroy(&sna->kgem, tmp->src.bo);
+cleanup_dst:
+ if (tmp->redirect.real_bo)
+ kgem_bo_destroy(&sna->kgem, tmp->dst.bo);
+ return FALSE;
+}
+
+static void
+gen2_render_reset(struct sna *sna)
+{
+ sna->render_state.gen2.need_invariant = TRUE;
+ sna->render_state.gen2.vertex_offset = 0;
+}
+
+static void
+gen2_render_flush(struct sna *sna)
+{
+ gen2_vertex_flush(sna);
+}
+
+static void
+gen2_render_context_switch(struct sna *sna,
+ int new_mode)
+{
+}
+
+static void
+gen2_render_fini(struct sna *sna)
+{
+}
+
+Bool gen2_render_init(struct sna *sna)
+{
+ struct sna_render *render = &sna->render;
+
+ gen2_render_reset(sna);
+
+ /* Use the BLT (and overlay) for everything except when forced to
+ * use the texture combiners.
+ */
+ render->composite = gen2_render_composite;
+
+ /* XXX Y-tiling copies */
+
+ render->reset = gen2_render_reset;
+ render->flush = gen2_render_flush;
+ render->context_switch = gen2_render_context_switch;
+ render->fini = gen2_render_fini;
+
+ render->max_3d_size = 2048;
+ return TRUE;
+}