i830_render.c revision fa225cbc
1/*
2 * Copyright © 2006 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Wang Zhenyu <zhenyu.z.wang@intel.com>
25 *    Eric Anholt <eric@anholt.net>
26 *
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include "xf86.h"
34#include "i830.h"
35#include "i830_reg.h"
36
37struct blendinfo {
38    Bool dst_alpha;
39    Bool src_alpha;
40    uint32_t src_blend;
41    uint32_t dst_blend;
42};
43
44struct formatinfo {
45    int fmt;
46    uint32_t card_fmt;
47};
48
49#define TB0C_LAST_STAGE	(1 << 31)
50#define TB0C_RESULT_SCALE_1X		(0 << 29)
51#define TB0C_RESULT_SCALE_2X		(1 << 29)
52#define TB0C_RESULT_SCALE_4X		(2 << 29)
53#define TB0C_OP_MODULE			(3 << 25)
54#define TB0C_OUTPUT_WRITE_CURRENT	(0 << 24)
55#define TB0C_OUTPUT_WRITE_ACCUM		(1 << 24)
56#define TB0C_ARG3_REPLICATE_ALPHA 	(1<<23)
57#define TB0C_ARG3_INVERT		(1<<22)
58#define TB0C_ARG3_SEL_XXX
59#define TB0C_ARG2_REPLICATE_ALPHA 	(1<<17)
60#define TB0C_ARG2_INVERT		(1<<16)
61#define TB0C_ARG2_SEL_ONE		(0 << 12)
62#define TB0C_ARG2_SEL_FACTOR		(1 << 12)
63#define TB0C_ARG2_SEL_TEXEL0		(6 << 12)
64#define TB0C_ARG2_SEL_TEXEL1		(7 << 12)
65#define TB0C_ARG2_SEL_TEXEL2		(8 << 12)
66#define TB0C_ARG2_SEL_TEXEL3		(9 << 12)
67#define TB0C_ARG1_REPLICATE_ALPHA 	(1<<11)
68#define TB0C_ARG1_INVERT		(1<<10)
69#define TB0C_ARG1_SEL_ONE		(0 << 6)
70#define TB0C_ARG1_SEL_TEXEL0		(6 << 6)
71#define TB0C_ARG1_SEL_TEXEL1		(7 << 6)
72#define TB0C_ARG1_SEL_TEXEL2		(8 << 6)
73#define TB0C_ARG1_SEL_TEXEL3		(9 << 6)
74#define TB0C_ARG0_REPLICATE_ALPHA 	(1<<5)
75#define TB0C_ARG0_SEL_XXX
76
77#define TB0A_CTR_STAGE_ENABLE 		(1<<31)
78#define TB0A_RESULT_SCALE_1X		(0 << 29)
79#define TB0A_RESULT_SCALE_2X		(1 << 29)
80#define TB0A_RESULT_SCALE_4X		(2 << 29)
81#define TB0A_OP_MODULE			(3 << 25)
82#define TB0A_OUTPUT_WRITE_CURRENT	(0<<24)
83#define TB0A_OUTPUT_WRITE_ACCUM		(1<<24)
84#define TB0A_CTR_STAGE_SEL_BITS_XXX
85#define TB0A_ARG3_SEL_XXX
86#define TB0A_ARG3_INVERT		(1<<17)
87#define TB0A_ARG2_INVERT		(1<<16)
88#define TB0A_ARG2_SEL_ONE		(0 << 12)
89#define TB0A_ARG2_SEL_TEXEL0		(6 << 12)
90#define TB0A_ARG2_SEL_TEXEL1		(7 << 12)
91#define TB0A_ARG2_SEL_TEXEL2		(8 << 12)
92#define TB0A_ARG2_SEL_TEXEL3		(9 << 12)
93#define TB0A_ARG1_INVERT		(1<<10)
94#define TB0A_ARG1_SEL_ONE		(0 << 6)
95#define TB0A_ARG1_SEL_TEXEL0		(6 << 6)
96#define TB0A_ARG1_SEL_TEXEL1		(7 << 6)
97#define TB0A_ARG1_SEL_TEXEL2		(8 << 6)
98#define TB0A_ARG1_SEL_TEXEL3		(9 << 6)
99
100static struct blendinfo i830_blend_op[] = {
101    /* Clear */
102    {0, 0, BLENDFACTOR_ZERO, 		BLENDFACTOR_ZERO},
103    /* Src */
104    {0, 0, BLENDFACTOR_ONE, 		BLENDFACTOR_ZERO},
105    /* Dst */
106    {0, 0, BLENDFACTOR_ZERO,		BLENDFACTOR_ONE},
107    /* Over */
108    {0, 1, BLENDFACTOR_ONE,		BLENDFACTOR_INV_SRC_ALPHA},
109    /* OverReverse */
110    {1, 0, BLENDFACTOR_INV_DST_ALPHA,	BLENDFACTOR_ONE},
111    /* In */
112    {1, 0, BLENDFACTOR_DST_ALPHA,	BLENDFACTOR_ZERO},
113    /* InReverse */
114    {0, 1, BLENDFACTOR_ZERO,		BLENDFACTOR_SRC_ALPHA},
115    /* Out */
116    {1, 0, BLENDFACTOR_INV_DST_ALPHA,	BLENDFACTOR_ZERO},
117    /* OutReverse */
118    {0, 1, BLENDFACTOR_ZERO,		BLENDFACTOR_INV_SRC_ALPHA},
119    /* Atop */
120    {1, 1, BLENDFACTOR_DST_ALPHA,	BLENDFACTOR_INV_SRC_ALPHA},
121    /* AtopReverse */
122    {1, 1, BLENDFACTOR_INV_DST_ALPHA,	BLENDFACTOR_SRC_ALPHA},
123    /* Xor */
124    {1, 1, BLENDFACTOR_INV_DST_ALPHA,	BLENDFACTOR_INV_SRC_ALPHA},
125    /* Add */
126    {0, 0, BLENDFACTOR_ONE, 		BLENDFACTOR_ONE},
127};
128
129/* The x8* formats could use MT_32BIT_X* on 855+, but since we implement
130 * workarounds for 830/845 anyway, we just rely on those whether the hardware
131 * could handle it for us or not.
132 */
133static struct formatinfo i830_tex_formats[] = {
134    {PICT_a8r8g8b8, MT_32BIT_ARGB8888 },
135    {PICT_x8r8g8b8, MT_32BIT_ARGB8888 },
136    {PICT_a8b8g8r8, MT_32BIT_ABGR8888 },
137    {PICT_x8b8g8r8, MT_32BIT_ABGR8888 },
138    {PICT_r5g6b5,   MT_16BIT_RGB565   },
139    {PICT_a1r5g5b5, MT_16BIT_ARGB1555 },
140    {PICT_x1r5g5b5, MT_16BIT_ARGB1555 },
141    {PICT_a8,       MT_8BIT_A8        },
142};
143
144static Bool i830_get_dest_format(PicturePtr pDstPicture, uint32_t *dst_format)
145{
146    switch (pDstPicture->format) {
147    case PICT_a8r8g8b8:
148    case PICT_x8r8g8b8:
149        *dst_format = COLR_BUF_ARGB8888;
150        break;
151    case PICT_r5g6b5:
152        *dst_format = COLR_BUF_RGB565;
153        break;
154    case PICT_a1r5g5b5:
155    case PICT_x1r5g5b5:
156        *dst_format = COLR_BUF_ARGB1555;
157        break;
158    case PICT_a8:
159        *dst_format = COLR_BUF_8BIT;
160        break;
161    case PICT_a4r4g4b4:
162    case PICT_x4r4g4b4:
163	*dst_format = COLR_BUF_ARGB4444;
164	break;
165    default:
166	{
167	    ScrnInfoPtr pScrn;
168
169	    pScrn = xf86Screens[pDstPicture->pDrawable->pScreen->myNum];
170	    I830FALLBACK("Unsupported dest format 0x%x\n",
171			 (int)pDstPicture->format);
172	}
173    }
174    *dst_format |= DSTORG_HORT_BIAS (0x8) | DSTORG_VERT_BIAS (0x8);
175    return TRUE;
176}
177
178
179static Bool i830_get_blend_cntl(ScrnInfoPtr pScrn, int op, PicturePtr pMask,
180				uint32_t dst_format, uint32_t *blendctl)
181{
182    uint32_t sblend, dblend;
183
184    sblend = i830_blend_op[op].src_blend;
185    dblend = i830_blend_op[op].dst_blend;
186
187    /* If there's no dst alpha channel, adjust the blend op so that we'll treat
188     * it as always 1.
189     */
190    if (PICT_FORMAT_A(dst_format) == 0 && i830_blend_op[op].dst_alpha) {
191        if (sblend == BLENDFACTOR_DST_ALPHA)
192            sblend = BLENDFACTOR_ONE;
193        else if (sblend == BLENDFACTOR_INV_DST_ALPHA)
194            sblend = BLENDFACTOR_ZERO;
195    }
196
197    /* For blending purposes, COLR_BUF_8BIT values show up in the green
198     * channel.  So we can't use the alpha channel.
199     */
200    if (dst_format == PICT_a8 && ((sblend == BLENDFACTOR_DST_ALPHA ||
201				   sblend == BLENDFACTOR_INV_DST_ALPHA))) {
202	I830FALLBACK("Can't do dst alpha blending with PICT_a8 dest.\n");
203    }
204
205    /* If the source alpha is being used, then we should only be in a case
206     * where the source blend factor is 0, and the source blend value is the
207     * mask channels multiplied by the source picture's alpha.
208     */
209    if (pMask && pMask->componentAlpha && PICT_FORMAT_RGB(pMask->format)
210	    && i830_blend_op[op].src_alpha) {
211        if (dblend == BLENDFACTOR_SRC_ALPHA) {
212            dblend = BLENDFACTOR_SRC_COLR;
213        } else if (dblend == BLENDFACTOR_INV_SRC_ALPHA) {
214            dblend = BLENDFACTOR_INV_SRC_COLR;
215        }
216    }
217
218    *blendctl = (sblend << S8_SRC_BLEND_FACTOR_SHIFT) |
219	(dblend << S8_DST_BLEND_FACTOR_SHIFT);
220
221    return TRUE;
222}
223
224static Bool i830_check_composite_texture(ScrnInfoPtr pScrn, PicturePtr pPict, int unit)
225{
226    if (pPict->repeatType > RepeatReflect)
227        I830FALLBACK("Unsupported picture repeat %d\n", pPict->repeatType);
228
229    if (pPict->filter != PictFilterNearest &&
230        pPict->filter != PictFilterBilinear)
231    {
232        I830FALLBACK("Unsupported filter 0x%x\n", pPict->filter);
233    }
234
235    if (pPict->pDrawable)
236    {
237	int w, h, i;
238
239	w = pPict->pDrawable->width;
240	h = pPict->pDrawable->height;
241	if ((w > 2048) || (h > 2048))
242	    I830FALLBACK("Picture w/h too large (%dx%d)\n", w, h);
243
244	for (i = 0; i < sizeof(i830_tex_formats) / sizeof(i830_tex_formats[0]);
245	     i++)
246	{
247	    if (i830_tex_formats[i].fmt == pPict->format)
248		break;
249	}
250	if (i == sizeof(i830_tex_formats) / sizeof(i830_tex_formats[0]))
251	    I830FALLBACK("Unsupported picture format 0x%x\n",
252			 (int)pPict->format);
253    }
254
255    return TRUE;
256}
257
258static uint32_t
259i8xx_get_card_format(PicturePtr pPict)
260{
261    int i;
262    for (i = 0; i < sizeof(i830_tex_formats) / sizeof(i830_tex_formats[0]);
263	    i++)
264    {
265	if (i830_tex_formats[i].fmt == pPict->format)
266	    return i830_tex_formats[i].card_fmt;
267    }
268    FatalError("Unsupported format type %d\n", pPict->format);
269}
270
271static void
272i830_texture_setup(PicturePtr pPict, PixmapPtr pPix, int unit)
273{
274
275    ScrnInfoPtr pScrn = xf86Screens[pPict->pDrawable->pScreen->myNum];
276    I830Ptr pI830 = I830PTR(pScrn);
277    uint32_t format, pitch, filter;
278    uint32_t wrap_mode;
279    uint32_t texcoordtype;
280
281    pitch = intel_get_pixmap_pitch(pPix);
282    pI830->scale_units[unit][0] = pPix->drawable.width;
283    pI830->scale_units[unit][1] = pPix->drawable.height;
284    pI830->transform[unit] = pPict->transform;
285
286    if (i830_transform_is_affine(pI830->transform[unit]))
287	texcoordtype = TEXCOORDTYPE_CARTESIAN;
288    else
289	texcoordtype = TEXCOORDTYPE_HOMOGENEOUS;
290
291    format = i8xx_get_card_format(pPict);
292
293    switch (pPict->repeatType) {
294    case RepeatNone:
295	wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
296	break;
297    case RepeatNormal:
298	wrap_mode = TEXCOORDMODE_WRAP;
299	break;
300    case RepeatPad:
301	wrap_mode = TEXCOORDMODE_CLAMP;
302	break;
303    case RepeatReflect:
304	wrap_mode = TEXCOORDMODE_MIRROR;
305	break;
306    default:
307	FatalError("Unknown repeat type %d\n", pPict->repeatType);
308    }
309
310    switch (pPict->filter) {
311    case PictFilterNearest:
312        filter = ((FILTER_NEAREST<<TM0S3_MAG_FILTER_SHIFT) |
313		  (FILTER_NEAREST<<TM0S3_MIN_FILTER_SHIFT));
314        break;
315    case PictFilterBilinear:
316        filter = ((FILTER_LINEAR<<TM0S3_MAG_FILTER_SHIFT) |
317		  (FILTER_LINEAR<<TM0S3_MIN_FILTER_SHIFT));
318        break;
319    default:
320	filter = 0;
321        FatalError("Bad filter 0x%x\n", pPict->filter);
322    }
323    filter |= (MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT);
324
325    {
326	if (pPix->drawable.bitsPerPixel == 8)
327	    format |= MAPSURF_8BIT;
328	else if (pPix->drawable.bitsPerPixel == 16)
329	    format |= MAPSURF_16BIT;
330	else
331	    format |= MAPSURF_32BIT;
332
333	BEGIN_BATCH(10);
334	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | LOAD_TEXTURE_MAP(unit) | 4);
335	OUT_RELOC_PIXMAP(pPix, I915_GEM_DOMAIN_SAMPLER, 0, TM0S0_USE_FENCE);
336	OUT_BATCH(((pPix->drawable.height - 1) << TM0S1_HEIGHT_SHIFT) |
337		  ((pPix->drawable.width - 1) << TM0S1_WIDTH_SHIFT) | format);
338	OUT_BATCH((pitch/4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D);
339	OUT_BATCH(filter);
340	OUT_BATCH(0); /* default color */
341	OUT_BATCH(_3DSTATE_MAP_COORD_SET_CMD | TEXCOORD_SET(unit) |
342		  ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL |
343		  texcoordtype | ENABLE_ADDR_V_CNTL |
344		  TEXCOORD_ADDR_V_MODE(wrap_mode) |
345		  ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(wrap_mode));
346	/* map texel stream */
347	OUT_BATCH(_3DSTATE_MAP_COORD_SETBIND_CMD);
348	if (unit == 0)
349	    OUT_BATCH(TEXBIND_SET0(TEXCOORDSRC_VTXSET_0) |
350		      TEXBIND_SET1(TEXCOORDSRC_KEEP) |
351		      TEXBIND_SET2(TEXCOORDSRC_KEEP) |
352		      TEXBIND_SET3(TEXCOORDSRC_KEEP));
353	else
354	    OUT_BATCH(TEXBIND_SET0(TEXCOORDSRC_VTXSET_0) |
355		      TEXBIND_SET1(TEXCOORDSRC_VTXSET_1) |
356		      TEXBIND_SET2(TEXCOORDSRC_KEEP) |
357		      TEXBIND_SET3(TEXCOORDSRC_KEEP));
358	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | (unit << 16) |
359		  DISABLE_TEX_STREAM_BUMP |
360		  ENABLE_TEX_STREAM_COORD_SET |
361		  TEX_STREAM_COORD_SET(unit) |
362		  ENABLE_TEX_STREAM_MAP_IDX |
363		  TEX_STREAM_MAP_IDX(unit));
364	ADVANCE_BATCH();
365     }
366}
367
368Bool
369i830_check_composite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
370		     PicturePtr pDstPicture)
371{
372    ScrnInfoPtr pScrn = xf86Screens[pDstPicture->pDrawable->pScreen->myNum];
373    uint32_t tmp1;
374
375    /* Check for unsupported compositing operations. */
376    if (op >= sizeof(i830_blend_op) / sizeof(i830_blend_op[0]))
377        I830FALLBACK("Unsupported Composite op 0x%x\n", op);
378
379    if (pMaskPicture != NULL && pMaskPicture->componentAlpha &&
380	    PICT_FORMAT_RGB(pMaskPicture->format)) {
381        /* Check if it's component alpha that relies on a source alpha and on
382         * the source value.  We can only get one of those into the single
383         * source value that we get to blend with.
384         */
385        if (i830_blend_op[op].src_alpha &&
386            (i830_blend_op[op].src_blend != BLENDFACTOR_ZERO))
387            	I830FALLBACK("Component alpha not supported with source "
388			     "alpha and source value blending.\n");
389    }
390
391    if (!i830_check_composite_texture(pScrn, pSrcPicture, 0))
392        I830FALLBACK("Check Src picture texture\n");
393    if (pMaskPicture != NULL && !i830_check_composite_texture(pScrn, pMaskPicture, 1))
394        I830FALLBACK("Check Mask picture texture\n");
395
396    if (!i830_get_dest_format(pDstPicture, &tmp1))
397	I830FALLBACK("Get Color buffer format\n");
398
399    return TRUE;
400}
401
402Bool
403i830_prepare_composite(int op, PicturePtr pSrcPicture,
404		       PicturePtr pMaskPicture, PicturePtr pDstPicture,
405		       PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
406{
407    ScrnInfoPtr pScrn = xf86Screens[pDstPicture->pDrawable->pScreen->myNum];
408    I830Ptr pI830 = I830PTR(pScrn);
409
410    pI830->render_src_picture = pSrcPicture;
411    pI830->render_src = pSrc;
412    pI830->render_mask_picture = pMaskPicture;
413    pI830->render_mask = pMask;
414    pI830->render_dst_picture = pDstPicture;
415    pI830->render_dst = pDst;
416
417    i830_exa_check_pitch_3d(pSrc);
418    if (pMask)
419	i830_exa_check_pitch_3d(pMask);
420    i830_exa_check_pitch_3d(pDst);
421
422    if (!i830_get_dest_format(pDstPicture, &pI830->render_dst_format))
423	return FALSE;
424
425    pI830->dst_coord_adjust = 0;
426    pI830->src_coord_adjust = 0;
427    pI830->mask_coord_adjust = 0;
428    if (pSrcPicture->filter == PictFilterNearest)
429	pI830->src_coord_adjust = 0.375;
430    if (pMask != NULL) {
431	pI830->mask_coord_adjust = 0;
432	if (pMaskPicture->filter == PictFilterNearest)
433	    pI830->mask_coord_adjust = 0.375;
434    } else {
435	pI830->transform[1] = NULL;
436	pI830->scale_units[1][0] = -1;
437	pI830->scale_units[1][1] = -1;
438    }
439
440    {
441	uint32_t cblend, ablend, blendctl;
442
443	/* If component alpha is active in the mask and the blend operation
444	 * uses the source alpha, then we know we don't need the source
445	 * value (otherwise we would have hit a fallback earlier), so we
446	 * provide the source alpha (src.A * mask.X) as output color.
447	 * Conversely, if CA is set and we don't need the source alpha, then
448	 * we produce the source value (src.X * mask.X) and the source alpha
449	 * is unused..  Otherwise, we provide the non-CA source value
450	 * (src.X * mask.A).
451	 *
452	 * The PICT_FORMAT_RGB(pict) == 0 fixups are not needed on 855+'s a8
453	 * pictures, but we need to implement it for 830/845 and there's no
454	 * harm done in leaving it in.
455	 */
456	cblend = TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_MODULE |
457		 TB0C_OUTPUT_WRITE_CURRENT;
458	ablend = TB0A_RESULT_SCALE_1X | TB0A_OP_MODULE |
459		 TB0A_OUTPUT_WRITE_CURRENT;
460
461	/* Get the source picture's channels into TBx_ARG1 */
462	if ((pMaskPicture != NULL &&
463	     pMaskPicture->componentAlpha &&
464	     PICT_FORMAT_RGB(pMaskPicture->format) &&
465	     i830_blend_op[op].src_alpha) || pDstPicture->format == PICT_a8)
466	{
467	    /* Producing source alpha value, so the first set of channels
468	     * is src.A instead of src.X.  We also do this if the destination
469	     * is a8, in which case src.G is what's written, and the other
470	     * channels are ignored.
471	     */
472	    if (PICT_FORMAT_A(pSrcPicture->format) != 0) {
473		ablend |= TB0A_ARG1_SEL_TEXEL0;
474		cblend |= TB0C_ARG1_SEL_TEXEL0 | TB0C_ARG1_REPLICATE_ALPHA;
475	    } else {
476		ablend |= TB0A_ARG1_SEL_ONE;
477		cblend |= TB0C_ARG1_SEL_ONE;
478	    }
479	} else {
480	    if (PICT_FORMAT_A(pSrcPicture->format) != 0) {
481		ablend |= TB0A_ARG1_SEL_TEXEL0;
482	    } else {
483		ablend |= TB0A_ARG1_SEL_ONE;
484	    }
485	    if (PICT_FORMAT_RGB(pSrcPicture->format) != 0)
486		cblend |= TB0C_ARG1_SEL_TEXEL0;
487	    else
488		cblend |= TB0C_ARG1_SEL_ONE | TB0C_ARG1_INVERT; /* 0.0 */
489	}
490
491	if (pMask) {
492	    if (pDstPicture->format != PICT_a8 &&
493		(pMaskPicture->componentAlpha &&
494		 PICT_FORMAT_RGB(pMaskPicture->format)))
495	    {
496		cblend |= TB0C_ARG2_SEL_TEXEL1;
497	    } else {
498		if (PICT_FORMAT_A(pMaskPicture->format) != 0)
499		    cblend |= TB0C_ARG2_SEL_TEXEL1 |
500			TB0C_ARG2_REPLICATE_ALPHA;
501		else
502		    cblend |= TB0C_ARG2_SEL_ONE;
503	    }
504	    if (PICT_FORMAT_A(pMaskPicture->format) != 0)
505		ablend |= TB0A_ARG2_SEL_TEXEL1;
506	    else
507		ablend |= TB0A_ARG2_SEL_ONE;
508	} else {
509	    cblend |= TB0C_ARG2_SEL_ONE;
510	    ablend |= TB0A_ARG2_SEL_ONE;
511	}
512
513	if (!i830_get_blend_cntl(pScrn, op, pMaskPicture, pDstPicture->format,
514				 &blendctl)) {
515	    return FALSE;
516	}
517
518	pI830->cblend = cblend;
519	pI830->ablend = ablend;
520	pI830->s8_blendctl = blendctl;
521    }
522
523    i830_debug_sync(pScrn);
524
525    pI830->needs_render_state_emit = TRUE;
526
527    return TRUE;
528}
529
530static void
531i830_emit_composite_state(ScrnInfoPtr pScrn)
532{
533    I830Ptr pI830 = I830PTR(pScrn);
534    uint32_t vf2;
535    uint32_t texcoordfmt = 0;
536
537    pI830->needs_render_state_emit = FALSE;
538
539    IntelEmitInvarientState(pScrn);
540    pI830->last_3d = LAST_3D_RENDER;
541
542    BEGIN_BATCH(21);
543
544    OUT_BATCH(_3DSTATE_BUF_INFO_CMD);
545    OUT_BATCH(BUF_3D_ID_COLOR_BACK| BUF_3D_USE_FENCE |
546	      BUF_3D_PITCH(intel_get_pixmap_pitch(pI830->render_dst)));
547    OUT_RELOC_PIXMAP(pI830->render_dst,
548		     I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
549
550    OUT_BATCH(_3DSTATE_DST_BUF_VARS_CMD);
551    OUT_BATCH(pI830->render_dst_format);
552
553    OUT_BATCH(_3DSTATE_DRAW_RECT_CMD);
554    OUT_BATCH(0);
555    OUT_BATCH(0); /* ymin, xmin */
556    OUT_BATCH(DRAW_YMAX(pI830->render_dst->drawable.height - 1) |
557	      DRAW_XMAX(pI830->render_dst->drawable.width - 1));
558    OUT_BATCH(0); /* yorig, xorig */
559
560    OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
561	      I1_LOAD_S(2) |
562	      I1_LOAD_S(3) |
563	      I1_LOAD_S(8) |
564	      2);
565    if (pI830->render_mask)
566	vf2 = 2 << 12; /* 2 texture coord sets */
567    else
568	vf2 = 1 << 12;
569    OUT_BATCH(vf2); /* number of coordinate sets */
570    OUT_BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
571    OUT_BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD | pI830->s8_blendctl |
572	      S8_ENABLE_COLOR_BUFFER_WRITE);
573
574    OUT_BATCH(_3DSTATE_INDPT_ALPHA_BLEND_CMD | DISABLE_INDPT_ALPHA_BLEND);
575
576    OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
577	      LOAD_TEXTURE_BLEND_STAGE(0)|1);
578    OUT_BATCH(pI830->cblend);
579    OUT_BATCH(pI830->ablend);
580
581    OUT_BATCH(_3DSTATE_ENABLES_1_CMD | DISABLE_LOGIC_OP |
582	      DISABLE_STENCIL_TEST | DISABLE_DEPTH_BIAS |
583	      DISABLE_SPEC_ADD | DISABLE_FOG | DISABLE_ALPHA_TEST |
584	      ENABLE_COLOR_BLEND | DISABLE_DEPTH_TEST);
585    /* We have to explicitly say we don't want write disabled */
586    OUT_BATCH(_3DSTATE_ENABLES_2_CMD | ENABLE_COLOR_MASK |
587	      DISABLE_STENCIL_WRITE | ENABLE_TEX_CACHE |
588	      DISABLE_DITHER | ENABLE_COLOR_WRITE |
589	      DISABLE_DEPTH_WRITE);
590
591    if (i830_transform_is_affine(pI830->render_src_picture->transform))
592	texcoordfmt |= (TEXCOORDFMT_2D << 0);
593    else
594	texcoordfmt |= (TEXCOORDFMT_3D << 0);
595    if (pI830->render_mask) {
596	if (i830_transform_is_affine(pI830->render_mask_picture->transform))
597	    texcoordfmt |= (TEXCOORDFMT_2D << 2);
598	else
599	    texcoordfmt |= (TEXCOORDFMT_3D << 2);
600    }
601    OUT_BATCH(_3DSTATE_VERTEX_FORMAT_2_CMD | texcoordfmt);
602
603    ADVANCE_BATCH();
604
605    i830_texture_setup(pI830->render_src_picture, pI830->render_src, 0);
606    if (pI830->render_mask) {
607	i830_texture_setup(pI830->render_mask_picture,
608			   pI830->render_mask, 1);
609    }
610}
611
612/* Emit the vertices for a single composite rectangle.
613 *
614 * This function is no longer shared between i830 and i915 generation code.
615 */
616static void
617i830_emit_composite_primitive(PixmapPtr pDst,
618			      int srcX, int srcY,
619			      int maskX, int maskY,
620			      int dstX, int dstY,
621			      int w, int h)
622{
623    ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
624    I830Ptr pI830 = I830PTR(pScrn);
625    Bool is_affine_src, is_affine_mask = TRUE;
626    int per_vertex, num_floats;
627    float src_x[3], src_y[3], src_w[3], mask_x[3], mask_y[3], mask_w[3];
628
629    per_vertex = 2; /* dest x/y */
630
631    {
632	float x = srcX + pI830->src_coord_adjust;
633	float y = srcY + pI830->src_coord_adjust;
634
635	is_affine_src = i830_transform_is_affine (pI830->transform[0]);
636	if (is_affine_src) {
637	    if (!i830_get_transformed_coordinates(x, y,
638						  pI830->transform[0],
639						  &src_x[0], &src_y[0]))
640		return;
641
642	    if (!i830_get_transformed_coordinates(x, y + h,
643						  pI830->transform[0],
644						  &src_x[1], &src_y[1]))
645		return;
646
647	    if (!i830_get_transformed_coordinates(x + w, y + h,
648						  pI830->transform[0],
649						  &src_x[2], &src_y[2]))
650		return;
651
652	    per_vertex += 2;    /* src x/y */
653	} else {
654	    if (!i830_get_transformed_coordinates_3d(x, y,
655						     pI830->transform[0],
656						     &src_x[0],
657						     &src_y[0],
658						     &src_w[0]))
659		return;
660
661	    if (!i830_get_transformed_coordinates_3d(x, y + h,
662						     pI830->transform[0],
663						     &src_x[1],
664						     &src_y[1],
665						     &src_w[1]))
666		return;
667
668	    if (!i830_get_transformed_coordinates_3d(x + w, y + h,
669						     pI830->transform[0],
670						     &src_x[2],
671						     &src_y[2],
672						     &src_w[2]))
673		return;
674
675	    per_vertex += 3;    /* src x/y/w */
676	}
677    }
678
679    if (pI830->render_mask) {
680	float x = maskX + pI830->mask_coord_adjust;
681	float y = maskY + pI830->mask_coord_adjust;
682
683	is_affine_mask = i830_transform_is_affine (pI830->transform[1]);
684	if (is_affine_mask) {
685	    if (!i830_get_transformed_coordinates(x, y,
686						  pI830->transform[1],
687						  &mask_x[0], &mask_y[0]))
688		return;
689
690	    if (!i830_get_transformed_coordinates(x, y + h,
691						  pI830->transform[1],
692						  &mask_x[1], &mask_y[1]))
693		return;
694
695	    if (!i830_get_transformed_coordinates(x + w, y + h,
696						  pI830->transform[1],
697						  &mask_x[2], &mask_y[2]))
698		return;
699
700	    per_vertex += 2;	/* mask x/y */
701	} else {
702	    if (!i830_get_transformed_coordinates_3d(x, y,
703						     pI830->transform[1],
704						     &mask_x[0],
705						     &mask_y[0],
706						     &mask_w[0]))
707		return;
708
709	    if (!i830_get_transformed_coordinates_3d(x, y + h,
710						     pI830->transform[1],
711						     &mask_x[1],
712						     &mask_y[1],
713						     &mask_w[1]))
714		return;
715
716	    if (!i830_get_transformed_coordinates_3d(x + w, y + h,
717						     pI830->transform[1],
718						     &mask_x[2],
719						     &mask_y[2],
720						     &mask_w[2]))
721		return;
722
723	    per_vertex += 3;	/* mask x/y/w */
724	}
725    }
726
727    num_floats = 3 * per_vertex;
728
729    BEGIN_BATCH(1 + num_floats);
730
731    OUT_BATCH(PRIM3D_INLINE | PRIM3D_RECTLIST | (num_floats-1));
732    OUT_BATCH_F(pI830->dst_coord_adjust + dstX + w);
733    OUT_BATCH_F(pI830->dst_coord_adjust + dstY + h);
734    OUT_BATCH_F(src_x[2] / pI830->scale_units[0][0]);
735    OUT_BATCH_F(src_y[2] / pI830->scale_units[0][1]);
736    if (!is_affine_src) {
737	OUT_BATCH_F(src_w[2]);
738    }
739    if (pI830->render_mask) {
740	OUT_BATCH_F(mask_x[2] / pI830->scale_units[1][0]);
741	OUT_BATCH_F(mask_y[2] / pI830->scale_units[1][1]);
742	if (!is_affine_mask) {
743	    OUT_BATCH_F(mask_w[2]);
744	}
745    }
746
747    OUT_BATCH_F(pI830->dst_coord_adjust + dstX);
748    OUT_BATCH_F(pI830->dst_coord_adjust + dstY + h);
749    OUT_BATCH_F(src_x[1] / pI830->scale_units[0][0]);
750    OUT_BATCH_F(src_y[1] / pI830->scale_units[0][1]);
751    if (!is_affine_src) {
752	OUT_BATCH_F(src_w[1]);
753    }
754    if (pI830->render_mask) {
755	OUT_BATCH_F(mask_x[1] / pI830->scale_units[1][0]);
756	OUT_BATCH_F(mask_y[1] / pI830->scale_units[1][1]);
757	if (!is_affine_mask) {
758	    OUT_BATCH_F(mask_w[1]);
759	}
760    }
761
762    OUT_BATCH_F(pI830->dst_coord_adjust + dstX);
763    OUT_BATCH_F(pI830->dst_coord_adjust + dstY);
764    OUT_BATCH_F(src_x[0] / pI830->scale_units[0][0]);
765    OUT_BATCH_F(src_y[0] / pI830->scale_units[0][1]);
766    if (!is_affine_src) {
767	OUT_BATCH_F(src_w[0]);
768    }
769    if (pI830->render_mask) {
770	OUT_BATCH_F(mask_x[0] / pI830->scale_units[1][0]);
771	OUT_BATCH_F(mask_y[0] / pI830->scale_units[1][1]);
772	if (!is_affine_mask) {
773	    OUT_BATCH_F(mask_w[0]);
774	}
775    }
776
777    ADVANCE_BATCH();
778}
779
780
781/**
782 * Do a single rectangle composite operation.
783 */
784void
785i830_composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
786	       int dstX, int dstY, int w, int h)
787{
788    ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
789    I830Ptr pI830 = I830PTR(pScrn);
790
791    intel_batch_start_atomic(pScrn,
792			     58 + /* invarient */
793			     22 + /* setup */
794			     20 + /* 2 * setup_texture */
795			     1 + 30 /* verts */);
796
797    if (pI830->needs_render_state_emit)
798	i830_emit_composite_state(pScrn);
799
800    i830_emit_composite_primitive(pDst, srcX, srcY, maskX, maskY, dstX, dstY,
801				  w, h);
802
803    intel_batch_end_atomic(pScrn);
804
805    i830_debug_sync(pScrn);
806}
807
808void
809i830_batch_flush_notify(ScrnInfoPtr scrn)
810{
811    I830Ptr i830 = I830PTR(scrn);
812
813    i830->needs_render_state_emit = TRUE;
814}
815