r128_exa_render.c revision 42a55b46
1/*
2 * Copyright 2003 Eric Anholt
3 * Copyright 2003 Anders Carlsson
4 * Copyright 2012 Connor Behan
5 * Copyright 2012 Michel Dänzer
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Authors:
28 *    Anders Carlsson <andersca@gnome.org>
29 *    Eric Anholt <anholt@FreeBSD.org>
30 *    Connor Behan <connor.behan@gmail.com>
31 *    Michel Dänzer <michel.daenzer@amd.com>
32 *
33 */
34
35/* The following is based on the kdrive ATI driver. */
36
37#include <stdio.h>
38#include <string.h>
39
40static struct {
41    Bool dst_alpha;
42    Bool src_alpha;
43    CARD32 sblend;
44    CARD32 dblend;
45} R128BlendOp[] = {
46    /* Clear */
47    {0, 0, R128_ALPHA_BLEND_ZERO        , R128_ALPHA_BLEND_ZERO},
48    /* Src */
49    {0, 0, R128_ALPHA_BLEND_ONE         , R128_ALPHA_BLEND_ZERO},
50    /* Dst */
51    {0, 0, R128_ALPHA_BLEND_ZERO        , R128_ALPHA_BLEND_ONE},
52    /* Over */
53    {0, 1, R128_ALPHA_BLEND_ONE         , R128_ALPHA_BLEND_INVSRCALPHA},
54    /* OverReverse */
55    {1, 0, R128_ALPHA_BLEND_INVDSTALPHA , R128_ALPHA_BLEND_ONE},
56    /* In */
57    {1, 0, R128_ALPHA_BLEND_DSTALPHA    , R128_ALPHA_BLEND_ZERO},
58    /* InReverse */
59    {0, 1, R128_ALPHA_BLEND_ZERO        , R128_ALPHA_BLEND_SRCALPHA},
60    /* Out */
61    {1, 0, R128_ALPHA_BLEND_INVDSTALPHA , R128_ALPHA_BLEND_ZERO},
62    /* OutReverse */
63    {0, 1, R128_ALPHA_BLEND_ZERO        , R128_ALPHA_BLEND_INVSRCALPHA},
64    /* Atop */
65    {1, 1, R128_ALPHA_BLEND_DSTALPHA    , R128_ALPHA_BLEND_INVSRCALPHA},
66    /* AtopReverse */
67    {1, 1, R128_ALPHA_BLEND_INVDSTALPHA , R128_ALPHA_BLEND_SRCALPHA},
68    /* Xor */
69    {1, 1, R128_ALPHA_BLEND_INVDSTALPHA , R128_ALPHA_BLEND_INVSRCALPHA},
70    /* Add */
71    {0, 0, R128_ALPHA_BLEND_ONE         , R128_ALPHA_BLEND_ONE},
72};
73
74static Bool
75R128TransformAffineOrScaled(PictTransformPtr t)
76{
77    if (t == NULL) return TRUE;
78
79    /* the shaders don't handle scaling either */
80    return t->matrix[2][0] == 0 && t->matrix[2][1] == 0 && t->matrix[2][2] == IntToxFixed(1);
81}
82
83static PixmapPtr
84R128GetDrawablePixmap(DrawablePtr pDrawable)
85{
86    if (pDrawable->type == DRAWABLE_WINDOW)
87	return pDrawable->pScreen->GetWindowPixmap((WindowPtr)pDrawable);
88    else
89	return (PixmapPtr)pDrawable;
90}
91
92static PixmapPtr
93R128SolidPixmap(ScreenPtr pScreen, uint32_t solid)
94{
95    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
96    R128InfoPtr   info      = R128PTR(pScrn);
97    PixmapPtr	  pPix	    = pScreen->CreatePixmap(pScreen, 1, 1, 32, 0);
98
99    exaMoveInPixmap(pPix);
100    if (!exaDrawableIsOffscreen(&pPix->drawable)) {
101        pScreen->DestroyPixmap(pPix);
102	return NULL;
103    }
104    info->ExaDriver->WaitMarker(pScreen, 0);
105    memcpy(info->ExaDriver->memoryBase + exaGetPixmapOffset(pPix), &solid, 4);
106
107    return pPix;
108}
109
110static Bool
111R128GetDatatypePict1(uint32_t format, uint32_t *type)
112{
113    switch(format) {
114    case PICT_r5g6b5:
115	*type = R128_DATATYPE_RGB565;
116	return TRUE;
117    case PICT_x1r5g5b5:
118	*type = R128_DATATYPE_ARGB1555;
119	return TRUE;
120    case PICT_x8r8g8b8:
121	*type = R128_DATATYPE_ARGB8888;
122	return TRUE;
123    default:
124        return FALSE;
125    }
126}
127
128static Bool
129R128GetDatatypePict2(uint32_t format, uint32_t *type)
130{
131    switch(format) {
132    case PICT_a8:
133        *type = R128_DATATYPE_RGB8;
134	return TRUE;
135    case PICT_r5g6b5:
136	*type = R128_DATATYPE_RGB565;
137	return TRUE;
138    case PICT_a8r8g8b8:
139	*type = R128_DATATYPE_ARGB8888;
140	return TRUE;
141    default:
142        return FALSE;
143    }
144}
145
146static Bool
147R128CheckCompositeTexture(PicturePtr pPict, PicturePtr pDstPict, int op)
148{
149    ScreenPtr     pScreen   = pDstPict->pDrawable->pScreen;
150    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
151
152    unsigned int repeatType = pPict->repeat ? pPict->repeatType : RepeatNone;
153    uint32_t tmp1;
154
155    if (!R128GetDatatypePict2(pPict->format, &tmp1)) return FALSE;
156
157    if (pPict->pDrawable) {
158        int w = pPict->pDrawable->width;
159        int h = pPict->pDrawable->height;
160
161        if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)) {
162            R128TRACE(("NPOT repeat unsupported (%dx%d)\n", w, h));
163	    return FALSE;
164        }
165    }
166
167    if (pPict->filter != PictFilterNearest && pPict->filter != PictFilterBilinear) {
168	R128TRACE(("Unsupported filter 0x%x\n", pPict->filter));
169	return FALSE;
170    }
171
172    /* The radeon driver has a long explanation about this part that I don't really understand */
173    if (pPict->transform != 0 && repeatType == RepeatNone && PICT_FORMAT_A(pPict->format) == 0) {
174	if (!(((op == PictOpSrc) || (op == PictOpClear)) && (PICT_FORMAT_A(pDstPict->format) == 0))) {
175	    R128TRACE(("REPEAT_NONE unsupported for transformed xRGB source\n"));
176	    return FALSE;
177	}
178    }
179    if (!R128TransformAffineOrScaled(pPict->transform)) {
180	R128TRACE(("Non-affine transforms not supported\n"));
181	return FALSE;
182    }
183
184    return TRUE;
185}
186
187static Bool
188R128CCECheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture)
189{
190    ScreenPtr     pScreen   = pDstPicture->pDrawable->pScreen;
191    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
192
193    PixmapPtr pSrcPixmap, pDstPixmap;
194    uint32_t tmp1;
195
196    /* Check for unsupported compositing operations. */
197    if (op >= sizeof(R128BlendOp) / sizeof(R128BlendOp[0])) {
198	R128TRACE(("Unsupported Composite op 0x%x\n", op));
199	return FALSE;
200    }
201
202    pDstPixmap = R128GetDrawablePixmap(pDstPicture->pDrawable);
203    if (pDstPixmap->drawable.width > 1024 || pDstPixmap->drawable.height > 1024) {
204	R128TRACE(("Dest w/h too large (%d,%d).\n", pDstPixmap->drawable.width, pDstPixmap->drawable.height));
205	return FALSE;
206    }
207
208    if (pSrcPicture->pDrawable) {
209        pSrcPixmap = R128GetDrawablePixmap(pSrcPicture->pDrawable);
210        if (pSrcPixmap->drawable.width > 1024 || pSrcPixmap->drawable.height > 1024) {
211	    R128TRACE(("Source w/h too large (%d,%d).\n", pSrcPixmap->drawable.width, pSrcPixmap->drawable.height));
212	    return FALSE;
213        }
214    } else if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill) {
215        R128TRACE(("Gradient pictures not supported yet\n"));
216	return FALSE;
217    }
218
219    if (pDstPicture->format == PICT_a8) {
220        if (R128BlendOp[op].src_alpha || R128BlendOp[op].dst_alpha || pMaskPicture != NULL) {
221	    R128TRACE(("Alpha blending unsupported with A8 dst?\n"));
222	    return FALSE;
223	}
224    } else {
225        if (!R128GetDatatypePict1(pDstPicture->format, &tmp1)) return FALSE;
226    }
227
228    if (pMaskPicture) {
229        PixmapPtr pMaskPixmap;
230
231        if (pMaskPicture->pDrawable) {
232	    pMaskPixmap = R128GetDrawablePixmap(pMaskPicture->pDrawable);
233            if (pMaskPixmap->drawable.width > 1024 || pMaskPixmap->drawable.height > 1024) {
234	        R128TRACE(("Mask w/h too large (%d,%d).\n", pMaskPixmap->drawable.width, pMaskPixmap->drawable.height));
235	        return FALSE;
236            }
237	} else if (pMaskPicture->pSourcePict->type != SourcePictTypeSolidFill) {
238	    R128TRACE(("Gradient pictures not supported yet\n"));
239	    return FALSE;
240	}
241
242	if (pMaskPicture->componentAlpha && R128BlendOp[op].src_alpha) {
243	    R128TRACE(("Component alpha not supported with source alpha blending\n"));
244	    return FALSE;
245	}
246
247	if (!R128CheckCompositeTexture(pMaskPicture, pDstPicture, op)) return FALSE;
248    }
249
250    if (!R128CheckCompositeTexture(pSrcPicture, pDstPicture, op)) return FALSE;
251    return TRUE;
252}
253
254static Bool
255R128TextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit, uint32_t *txsize, uint32_t *tex_cntl_c, Bool trying_solid)
256{
257    ScreenPtr     pScreen   = pPix->drawable.pScreen;
258    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
259    R128InfoPtr   info      = R128PTR(pScrn);
260
261    int w, h, bytepp, shift, l2w, l2h, l2p, pitch;
262
263    if (pPict->pDrawable) {
264	w = pPict->pDrawable->width;
265	h = pPict->pDrawable->height;
266    } else {
267	w = h = 1;
268    }
269
270    pitch = exaGetPixmapPitch(pPix);
271    if ((pitch & (pitch - 1)) != 0) {
272        R128TRACE(("NPOT pitch 0x%x unsupported\n", pitch));
273	return FALSE;
274    }
275
276    if (!R128GetDatatypePict2(pPict->format, tex_cntl_c)) return FALSE;
277
278    bytepp = PICT_FORMAT_BPP(pPict->format) / 8;
279    *tex_cntl_c |= R128_MIP_MAP_DISABLE;
280
281    if (pPict->filter == PictFilterBilinear) {
282        *tex_cntl_c |= R128_MIN_BLEND_LINEAR | R128_MAG_BLEND_LINEAR;
283    } else if (pPict->filter == PictFilterNearest) {
284	*tex_cntl_c |= R128_MIN_BLEND_NEAREST | R128_MAG_BLEND_NEAREST;
285    } else {
286	R128TRACE(("Bad filter 0x%x\n", pPict->filter));
287	return FALSE;
288    }
289
290    if (unit == 0) {
291        shift = 0;
292    } else {
293        shift = 16;
294        *tex_cntl_c |= R128_SEC_SELECT_SEC_ST;
295    }
296
297    l2w = R128MinBits(w) - 1;
298    l2h = R128MinBits(h) - 1;
299    l2p = R128MinBits(pitch / bytepp) - 1;
300
301    if (pPict->repeat && w == 1 && h == 1) {
302        l2p = 0;
303    } else if (pPict->repeat && l2p != l2w) {
304        R128TRACE(("Repeat not supported for pitch != width\n"));
305	return FALSE;
306    }
307
308    l2w = l2p;
309    /* This is required to handle NPOT height */
310    if ((unit == 1) || (unit == 0 && !pPict->repeat && !trying_solid)) l2h++;
311
312    info->state_2d.widths[unit] = 1 << l2w;
313    info->state_2d.heights[unit] = 1 << l2h;
314    *txsize |= l2p << (R128_TEX_PITCH_SHIFT + shift);
315    *txsize |= ((w > h) ? l2w : l2h) << (R128_TEX_SIZE_SHIFT + shift);
316    *txsize |= l2h << (R128_TEX_HEIGHT_SHIFT + shift);
317
318    if (pPict->transform != 0) {
319        info->state_2d.is_transform[unit] = TRUE;
320        info->state_2d.transform[unit] = pPict->transform;
321    } else {
322        info->state_2d.is_transform[unit] = FALSE;
323    }
324
325    return TRUE;
326}
327
328/* The composite preparation commands that are the same every time can
329 * just be written once.
330 */
331#define COMPOSITE_SETUP()				\
332do {							\
333    BEGIN_RING( 10 );					\
334							\
335    OUT_RING_REG(R128_SCALE_3D_CNTL,			\
336		    R128_SCALE_3D_TEXMAP_SHADE |	\
337		    R128_SCALE_PIX_REPLICATE |		\
338		    R128_TEX_CACHE_SPLIT |		\
339		    R128_TEX_MAP_ALPHA_IN_TEXTURE |	\
340		    R128_TEX_CACHE_LINE_SIZE_4QW);	\
341    OUT_RING_REG(R128_SETUP_CNTL,			\
342		    R128_COLOR_SOLID_COLOR |		\
343		    R128_PRIM_TYPE_TRI |		\
344		    R128_TEXTURE_ST_MULT_W |		\
345		    R128_STARTING_VERTEX_1 |		\
346		    R128_ENDING_VERTEX_3 |		\
347		    R128_SUB_PIX_4BITS);		\
348    OUT_RING_REG(R128_PM4_VC_FPU_SETUP,			\
349		    R128_FRONT_DIR_CCW |		\
350		    R128_BACKFACE_CULL |		\
351		    R128_FRONTFACE_SOLID |		\
352		    R128_FPU_COLOR_SOLID |		\
353		    R128_FPU_SUB_PIX_4BITS |		\
354		    R128_FPU_MODE_3D |			\
355		    R128_TRAP_BITS_DISABLE |		\
356		    R128_XFACTOR_2 |			\
357		    R128_YFACTOR_2 |			\
358		    R128_FLAT_SHADE_VERTEX_OGL |	\
359		    R128_FPU_ROUND_TRUNCATE |		\
360		    R128_WM_SEL_8DW);			\
361    OUT_RING_REG(R128_PLANE_3D_MASK_C, 0xffffffff);	\
362    OUT_RING_REG(R128_CONSTANT_COLOR_C, 0xff000000);	\
363							\
364    ADVANCE_RING();					\
365} while(0)
366
367static Bool
368R128CCEPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
369    PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
370{
371    ScreenPtr     pScreen   = pDst->drawable.pScreen;
372    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
373    R128InfoPtr   info      = R128PTR(pScrn);
374    unsigned char *R128MMIO = info->MMIO;
375    RING_LOCALS;
376
377    Bool add_src = FALSE;
378    Bool add_msk = FALSE;
379    uint32_t txsize = 0, prim_tex_cntl_c, sec_tex_cntl_c = 0, dstDatatype;
380    uint32_t src_pitch_offset, dst_pitch_offset, color_factor, in_color_factor, alpha_comb;
381    uint32_t sblend, dblend, blend_cntl, window_offset;
382    int i;
383
384    if (pDstPicture->format == PICT_a8) {
385        if (R128BlendOp[op].dst_alpha) {
386	    R128TRACE(("Can't dst alpha blend A8\n"));
387	    return FALSE;
388        }
389        dstDatatype = R128_DATATYPE_Y8;
390    } else {
391        if (!R128GetDatatypePict1(pDstPicture->format, &dstDatatype)) return FALSE;
392    }
393
394    if (!pSrc) {
395	pSrc = R128SolidPixmap(pScreen, cpu_to_le32(pSrcPicture->pSourcePict->solidFill.color));
396	if (!pSrc) {
397	    R128TRACE(("Failed to create solid scratch pixmap\n"));
398	    return FALSE;
399	}
400	add_src = TRUE;
401    }
402    if (pMaskPicture) {
403        info->state_2d.has_mask = TRUE;
404        if (!pMask) {
405	    pMask = R128SolidPixmap(pScreen, cpu_to_le32(pMaskPicture->pSourcePict->solidFill.color));
406	    if (!pMask) {
407	        if (!pSrcPicture->pDrawable)
408		    pScreen->DestroyPixmap(pSrc);
409		info->state_2d.has_mask = FALSE;
410	        R128TRACE(("Failed to create solid scratch pixmap\n"));
411	        return FALSE;
412	    }
413	    add_msk = TRUE;
414	}
415    } else {
416        info->state_2d.has_mask = FALSE;
417    }
418
419    if (!R128TextureSetup(pSrcPicture, pSrc, 0, &txsize, &prim_tex_cntl_c, (add_src || add_msk))) return FALSE;
420
421    if (pMask != NULL) {
422	info->state_2d.has_mask = TRUE;
423        if (!R128TextureSetup(pMaskPicture, pMask, 1, &txsize, &sec_tex_cntl_c, (add_src || add_msk))) return FALSE;
424    } else {
425	info->state_2d.has_mask = FALSE;
426	info->state_2d.is_transform[1] = FALSE;
427    }
428
429    if (!R128GetPixmapOffsetPitch(pDst, &dst_pitch_offset)) return FALSE;
430    if (!R128GetPixmapOffsetPitch(pSrc, &src_pitch_offset)) return FALSE;
431
432    info->state_2d.in_use = TRUE;
433    if (add_src) info->state_2d.src_pix = pSrc;
434    if (add_msk) info->state_2d.msk_pix = pMask;
435    sblend = R128BlendOp[op].sblend;
436    dblend = R128BlendOp[op].dblend;
437    if (PICT_FORMAT_A(pDstPicture->format) == 0 && R128BlendOp[op].dst_alpha) {
438        if (sblend == R128_ALPHA_BLEND_DSTALPHA)
439	    sblend = R128_ALPHA_BLEND_ONE;
440	else if (sblend == R128_ALPHA_BLEND_INVDSTALPHA)
441	    sblend = R128_ALPHA_BLEND_ZERO;
442    }
443    blend_cntl = (sblend << R128_ALPHA_BLEND_SRC_SHIFT) |
444		 (dblend << R128_ALPHA_BLEND_DST_SHIFT);
445
446    R128CCE_REFRESH( pScrn, info );
447
448    if (!info->state_2d.composite_setup) {
449        COMPOSITE_SETUP();
450	/* DRI and EXA are fighting over control of the texture hardware.
451	 * That means we need to set up the compositing hardware every time
452	 * while a 3D app is running and once after it closes.
453	 */
454	if (!info->have3DWindows)
455	    info->state_2d.composite_setup = TRUE;
456    }
457
458    /* We cannot guarantee that this register will stay zero - DRI needs it too. */
459    if (info->have3DWindows)
460        info->ExaDriver->WaitMarker(pScreen, 0);
461    window_offset = INREG(R128_WINDOW_XY_OFFSET);
462    info->state_2d.x_offset = (window_offset & 0xfff00000) >> R128_WINDOW_X_SHIFT;
463    info->state_2d.y_offset = (window_offset & 0x000fffff) >> R128_WINDOW_Y_SHIFT;
464
465    info->state_2d.dp_gui_master_cntl = (R128_GMC_DST_PITCH_OFFSET_CNTL |
466        R128_GMC_BRUSH_SOLID_COLOR |
467        (dstDatatype >> 8) |
468        R128_GMC_SRC_DATATYPE_COLOR |
469        R128_ROP[3].rop |
470        R128_DP_SRC_SOURCE_MEMORY |
471        R128_GMC_3D_FCN_EN |
472        R128_GMC_CLR_CMP_CNTL_DIS |
473        R128_GMC_AUX_CLIP_DIS |
474        R128_GMC_WR_MSK_DIS);
475    info->state_2d.dp_cntl = (R128_DST_X_LEFT_TO_RIGHT | R128_DST_Y_TOP_TO_BOTTOM);
476    info->state_2d.dp_brush_frgd_clr = 0xffffffff;
477    info->state_2d.dp_brush_bkgd_clr = 0x00000000;
478    info->state_2d.dp_src_frgd_clr = 0xffffffff;
479    info->state_2d.dp_src_bkgd_clr = 0x00000000;
480    info->state_2d.dp_write_mask = 0xffffffff;
481    info->state_2d.dst_pitch_offset = dst_pitch_offset;
482    info->state_2d.src_pitch_offset = src_pitch_offset;
483    info->state_2d.default_sc_bottom_right = (R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX);
484    EmitCCE2DState(pScrn);
485
486    BEGIN_RING( 6 );
487    OUT_RING_REG(R128_MISC_3D_STATE_CNTL_REG,
488        R128_MISC_SCALE_3D_TEXMAP_SHADE |
489        R128_MISC_SCALE_PIX_REPLICATE |
490        R128_ALPHA_COMB_ADD_CLAMP |
491        blend_cntl);
492    OUT_RING_REG(R128_TEX_CNTL_C,
493        R128_TEXMAP_ENABLE |
494        ((pMask != NULL) ? R128_SEC_TEXMAP_ENABLE : 0) |
495        R128_ALPHA_ENABLE |
496        R128_TEX_CACHE_FLUSH);
497    OUT_RING_REG(R128_PC_GUI_CTLSTAT, R128_PC_FLUSH_GUI);
498    ADVANCE_RING();
499
500    /* IN operator: Without a mask, only the first texture unit is enabled.
501     * With a mask, we put the source in the first unit and have it pass
502     * through as input to the 2nd.  The 2nd unit takes the incoming source
503     * pixel and modulates it with either the alpha or each of the channels
504     * in the mask, depending on componentAlpha.
505     */
506    BEGIN_RING( 15 );
507    /* R128_PRIM_TEX_CNTL_C,
508     * R128_PRIM_TEXTURE_COMBINE_CNTL_C,
509     * R128_TEX_SIZE_PITCH_C,
510     * R128_PRIM_TEX_0_OFFSET_C - R128_PRIM_TEX_10_OFFSET_C
511     */
512    OUT_RING(CCE_PACKET0(R128_PRIM_TEX_CNTL_C, 13));
513    OUT_RING(prim_tex_cntl_c);
514
515    /* If this is the only stage and the dest is a8, route the alpha result
516     * to the color (red channel, in particular), too.  Otherwise, be sure
517     * to zero out color channels of an a8 source.
518     */
519    if (pMaskPicture == NULL && pDstPicture->format == PICT_a8)
520        color_factor = R128_COLOR_FACTOR_ALPHA;
521    else if (pSrcPicture->format == PICT_a8)
522        color_factor = R128_COLOR_FACTOR_CONST_COLOR;
523    else
524        color_factor = R128_COLOR_FACTOR_TEX;
525
526    if (PICT_FORMAT_A(pSrcPicture->format) == 0)
527        alpha_comb = R128_COMB_ALPHA_COPY_INP;
528    else
529        alpha_comb = R128_COMB_ALPHA_DIS;
530
531    OUT_RING(R128_COMB_COPY |
532        color_factor |
533        R128_INPUT_FACTOR_INT_COLOR |
534        alpha_comb |
535        R128_ALPHA_FACTOR_TEX_ALPHA |
536        R128_INP_FACTOR_A_CONST_ALPHA);
537    OUT_RING(txsize);
538    /* We could save some output by only writing the offset register that
539     * will actually be used.  On the other hand, this is easy.
540     */
541    for (i = 0; i <= 10; i++)
542        OUT_RING(exaGetPixmapOffset(pSrc));
543    ADVANCE_RING();
544
545    if (pMask != NULL) {
546        BEGIN_RING( 14 );
547	/* R128_SEC_TEX_CNTL_C,
548	 * R128_SEC_TEXTURE_COMBINE_CNTL_C,
549	 * R128_SEC_TEX_0_OFFSET_C - R128_SEC_TEX_10_OFFSET_C
550	 */
551        OUT_RING(CCE_PACKET0(R128_SEC_TEX_CNTL_C, 12));
552        OUT_RING(sec_tex_cntl_c);
553
554        if (pDstPicture->format == PICT_a8) {
555            color_factor = R128_COLOR_FACTOR_ALPHA;
556            in_color_factor = R128_INPUT_FACTOR_PREV_ALPHA;
557        } else if (pMaskPicture->componentAlpha) {
558            color_factor = R128_COLOR_FACTOR_TEX;
559            in_color_factor = R128_INPUT_FACTOR_PREV_COLOR;
560        } else {
561            color_factor = R128_COLOR_FACTOR_ALPHA;
562            in_color_factor = R128_INPUT_FACTOR_PREV_COLOR;
563        }
564
565        OUT_RING(R128_COMB_MODULATE |
566            color_factor |
567            in_color_factor |
568            R128_COMB_ALPHA_MODULATE |
569            R128_ALPHA_FACTOR_TEX_ALPHA |
570            R128_INP_FACTOR_A_PREV_ALPHA);
571        for (i = 0; i <= 10; i++)
572            OUT_RING(exaGetPixmapOffset(pMask));
573	ADVANCE_RING();
574    }
575
576    return TRUE;
577}
578
579typedef union { float f; CARD32 i; } fi_type;
580
581static inline CARD32
582R128FloatAsInt(float val)
583{
584	fi_type fi;
585
586	fi.f = val;
587	return fi.i;
588}
589
590#define VTX_OUT_MASK(_dstX, _dstY, _srcX, _srcY, _maskX, _maskY)			\
591do {											\
592    OUT_RING(R128FloatAsInt((_dstX)));							\
593    OUT_RING(R128FloatAsInt(((float)(_dstY)) + 0.125));					\
594    OUT_RING(R128FloatAsInt(0.0));							\
595    OUT_RING(R128FloatAsInt(1.0));							\
596    OUT_RING(R128FloatAsInt((((float)(_srcX)) + 0.5) / (info->state_2d.widths[0])));	\
597    OUT_RING(R128FloatAsInt((((float)(_srcY)) + 0.5) / (info->state_2d.heights[0])));	\
598    OUT_RING(R128FloatAsInt((((float)(_maskX)) + 0.5) / (info->state_2d.widths[1])));	\
599    OUT_RING(R128FloatAsInt((((float)(_maskY)) + 0.5) / (info->state_2d.heights[1])));	\
600} while (0)
601
602#define VTX_OUT(_dstX, _dstY, _srcX, _srcY)						\
603do {								       			\
604    OUT_RING(R128FloatAsInt((_dstX)));							\
605    OUT_RING(R128FloatAsInt(((float)(_dstY)) + 0.125));					\
606    OUT_RING(R128FloatAsInt(0.0));							\
607    OUT_RING(R128FloatAsInt(1.0));							\
608    OUT_RING(R128FloatAsInt((((float)(_srcX)) + 0.5) / (info->state_2d.widths[0])));	\
609    OUT_RING(R128FloatAsInt((((float)(_srcY)) + 0.5) / (info->state_2d.heights[0])));	\
610} while (0)
611
612static void
613R128CCEComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, int w, int h)
614{
615    ScreenPtr     pScreen   = pDst->drawable.pScreen;
616    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
617    R128InfoPtr   info      = R128PTR(pScrn);
618    RING_LOCALS;
619
620    int srcXend, srcYend, maskXend, maskYend;
621    PictVector v;
622
623    srcXend = srcX + w;
624    srcYend = srcY + h;
625    maskXend = maskX + w;
626    maskYend = maskY + h;
627    if (info->state_2d.is_transform[0]) {
628        v.vector[0] = IntToxFixed(srcX);
629        v.vector[1] = IntToxFixed(srcY);
630        v.vector[2] = xFixed1;
631        PictureTransformPoint(info->state_2d.transform[0], &v);
632        srcX = xFixedToInt(v.vector[0]);
633        srcY = xFixedToInt(v.vector[1]);
634        v.vector[0] = IntToxFixed(srcXend);
635        v.vector[1] = IntToxFixed(srcYend);
636        v.vector[2] = xFixed1;
637        PictureTransformPoint(info->state_2d.transform[0], &v);
638        srcXend = xFixedToInt(v.vector[0]);
639        srcYend = xFixedToInt(v.vector[1]);
640    }
641    if (info->state_2d.is_transform[1]) {
642        v.vector[0] = IntToxFixed(maskX);
643        v.vector[1] = IntToxFixed(maskY);
644        v.vector[2] = xFixed1;
645        PictureTransformPoint(info->state_2d.transform[1], &v);
646        maskX = xFixedToInt(v.vector[0]);
647        maskY = xFixedToInt(v.vector[1]);
648        v.vector[0] = IntToxFixed(maskXend);
649        v.vector[1] = IntToxFixed(maskYend);
650        v.vector[2] = xFixed1;
651        PictureTransformPoint(info->state_2d.transform[1], &v);
652        maskXend = xFixedToInt(v.vector[0]);
653        maskYend = xFixedToInt(v.vector[1]);
654    }
655
656    dstX -= info->state_2d.x_offset;
657    dstY -= info->state_2d.y_offset;
658
659    R128CCE_REFRESH( pScrn, info );
660
661    if (info->state_2d.has_mask) {
662        BEGIN_RING( 3 + 4 * 8 );
663        OUT_RING(CCE_PACKET3(R128_CCE_PACKET3_3D_RNDR_GEN_PRIM, 1 + 4 * 8));
664
665	OUT_RING(R128_CCE_VC_FRMT_RHW |
666            R128_CCE_VC_FRMT_S_T |
667            R128_CCE_VC_FRMT_S2_T2);
668    } else {
669        BEGIN_RING( 3 + 4 * 6 );
670        OUT_RING(CCE_PACKET3(R128_CCE_PACKET3_3D_RNDR_GEN_PRIM, 1 + 4 * 6));
671
672	OUT_RING(R128_CCE_VC_FRMT_RHW |
673            R128_CCE_VC_FRMT_S_T);
674    }
675
676    OUT_RING(R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN |
677        R128_CCE_VC_CNTL_PRIM_WALK_RING |
678        (4 << R128_CCE_VC_CNTL_NUM_SHIFT));
679
680    if (info->state_2d.has_mask) {
681	VTX_OUT_MASK(dstX,     dstY,     srcX,    srcY,    maskX,    maskY);
682	VTX_OUT_MASK(dstX,     dstY + h, srcX,    srcYend, maskX,    maskYend);
683	VTX_OUT_MASK(dstX + w, dstY + h, srcXend, srcYend, maskXend, maskYend);
684	VTX_OUT_MASK(dstX + w, dstY,     srcXend, srcY,    maskXend, maskY);
685    } else {
686	VTX_OUT(dstX,     dstY,     srcX,    srcY);
687	VTX_OUT(dstX,     dstY + h, srcX,    srcYend);
688	VTX_OUT(dstX + w, dstY + h, srcXend, srcYend);
689	VTX_OUT(dstX + w, dstY,     srcXend, srcY);
690    }
691
692    ADVANCE_RING();
693}
694
695#define R128CCEDoneComposite R128Done
696