r128_exa_render.c revision 0496e070
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
106#if X_BYTE_ORDER == X_BIG_ENDIAN
107    if (pScrn->bitsPerPixel == 32)
108	R128CopySwap(info->ExaDriver->memoryBase + exaGetPixmapOffset(pPix), (uint8_t*)&solid, 4,
109		     APER_0_BIG_ENDIAN_32BPP_SWAP);
110    else if (pScrn->bitsPerPixel == 16)
111	R128CopySwap(info->ExaDriver->memoryBase + exaGetPixmapOffset(pPix), (uint8_t*)&solid, 4,
112		     APER_0_BIG_ENDIAN_16BPP_SWAP);
113    else
114	/* Fall through for 8 bpp */
115#endif
116    memcpy(info->ExaDriver->memoryBase + exaGetPixmapOffset(pPix), &solid, 4);
117
118    return pPix;
119}
120
121static Bool
122R128GetDatatypePict1(uint32_t format, uint32_t *type)
123{
124    switch(format) {
125    case PICT_r5g6b5:
126	*type = R128_DATATYPE_RGB565;
127	return TRUE;
128    case PICT_x1r5g5b5:
129	*type = R128_DATATYPE_ARGB1555;
130	return TRUE;
131    case PICT_x8r8g8b8:
132	*type = R128_DATATYPE_ARGB8888;
133	return TRUE;
134    default:
135        return FALSE;
136    }
137}
138
139static Bool
140R128GetDatatypePict2(uint32_t format, uint32_t *type)
141{
142    switch(format) {
143    case PICT_a8:
144        *type = R128_DATATYPE_RGB8;
145	return TRUE;
146    case PICT_r5g6b5:
147	*type = R128_DATATYPE_RGB565;
148	return TRUE;
149    case PICT_a8r8g8b8:
150	*type = R128_DATATYPE_ARGB8888;
151	return TRUE;
152    default:
153        return FALSE;
154    }
155}
156
157static Bool
158R128CheckCompositeTexture(PicturePtr pPict, PicturePtr pDstPict, int op)
159{
160    ScreenPtr     pScreen   = pDstPict->pDrawable->pScreen;
161    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
162
163    unsigned int repeatType = pPict->repeat ? pPict->repeatType : RepeatNone;
164    uint32_t tmp1;
165
166    if (!R128GetDatatypePict2(pPict->format, &tmp1)) return FALSE;
167
168    if (pPict->pDrawable) {
169        int w = pPict->pDrawable->width;
170        int h = pPict->pDrawable->height;
171
172        if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)) {
173            R128TRACE(("NPOT repeat unsupported (%dx%d)\n", w, h));
174	    return FALSE;
175        }
176    }
177
178    if (pPict->filter != PictFilterNearest && pPict->filter != PictFilterBilinear) {
179	R128TRACE(("Unsupported filter 0x%x\n", pPict->filter));
180	return FALSE;
181    }
182
183    /* The radeon driver has a long explanation about this part that I don't really understand */
184    if (pPict->transform != 0 && repeatType == RepeatNone && PICT_FORMAT_A(pPict->format) == 0) {
185	if (!(((op == PictOpSrc) || (op == PictOpClear)) && (PICT_FORMAT_A(pDstPict->format) == 0))) {
186	    R128TRACE(("REPEAT_NONE unsupported for transformed xRGB source\n"));
187	    return FALSE;
188	}
189    }
190    if (!R128TransformAffineOrScaled(pPict->transform)) {
191	R128TRACE(("Non-affine transforms not supported\n"));
192	return FALSE;
193    }
194
195    return TRUE;
196}
197
198static Bool
199R128CCECheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture)
200{
201    ScreenPtr     pScreen   = pDstPicture->pDrawable->pScreen;
202    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
203
204    PixmapPtr pSrcPixmap, pDstPixmap;
205    uint32_t tmp1;
206
207    /* Check for unsupported compositing operations. */
208    if (op >= sizeof(R128BlendOp) / sizeof(R128BlendOp[0])) {
209	R128TRACE(("Unsupported Composite op 0x%x\n", op));
210	return FALSE;
211    }
212
213    pDstPixmap = R128GetDrawablePixmap(pDstPicture->pDrawable);
214    if (pDstPixmap->drawable.width > 1024 || pDstPixmap->drawable.height > 1024) {
215	R128TRACE(("Dest w/h too large (%d,%d).\n", pDstPixmap->drawable.width, pDstPixmap->drawable.height));
216	return FALSE;
217    }
218
219    if (pSrcPicture->pDrawable) {
220        pSrcPixmap = R128GetDrawablePixmap(pSrcPicture->pDrawable);
221        if (pSrcPixmap->drawable.width > 1024 || pSrcPixmap->drawable.height > 1024) {
222	    R128TRACE(("Source w/h too large (%d,%d).\n", pSrcPixmap->drawable.width, pSrcPixmap->drawable.height));
223	    return FALSE;
224        }
225    } else if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill) {
226        R128TRACE(("Gradient pictures not supported yet\n"));
227	return FALSE;
228    }
229
230    if (pDstPicture->format == PICT_a8) {
231        if (R128BlendOp[op].src_alpha || R128BlendOp[op].dst_alpha || pMaskPicture != NULL) {
232	    R128TRACE(("Alpha blending unsupported with A8 dst?\n"));
233	    return FALSE;
234	}
235    } else {
236        if (!R128GetDatatypePict1(pDstPicture->format, &tmp1)) return FALSE;
237    }
238
239    if (pMaskPicture) {
240        PixmapPtr pMaskPixmap;
241
242        if (pMaskPicture->pDrawable) {
243	    pMaskPixmap = R128GetDrawablePixmap(pMaskPicture->pDrawable);
244            if (pMaskPixmap->drawable.width > 1024 || pMaskPixmap->drawable.height > 1024) {
245	        R128TRACE(("Mask w/h too large (%d,%d).\n", pMaskPixmap->drawable.width, pMaskPixmap->drawable.height));
246	        return FALSE;
247            }
248	} else if (pMaskPicture->pSourcePict->type != SourcePictTypeSolidFill) {
249	    R128TRACE(("Gradient pictures not supported yet\n"));
250	    return FALSE;
251	}
252
253	if (pMaskPicture->componentAlpha && R128BlendOp[op].src_alpha) {
254	    R128TRACE(("Component alpha not supported with source alpha blending\n"));
255	    return FALSE;
256	}
257
258	if (!R128CheckCompositeTexture(pMaskPicture, pDstPicture, op)) return FALSE;
259    }
260
261    if (!R128CheckCompositeTexture(pSrcPicture, pDstPicture, op)) return FALSE;
262    return TRUE;
263}
264
265static Bool
266R128TextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit, uint32_t *txsize, uint32_t *tex_cntl_c, Bool trying_solid)
267{
268    ScreenPtr     pScreen   = pPix->drawable.pScreen;
269    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
270    R128InfoPtr   info      = R128PTR(pScrn);
271
272    int w, h, bytepp, shift, l2w, l2h, l2p, pitch;
273
274    if (pPict->pDrawable) {
275	w = pPict->pDrawable->width;
276	h = pPict->pDrawable->height;
277    } else {
278	w = h = 1;
279    }
280
281    pitch = exaGetPixmapPitch(pPix);
282    if ((pitch & (pitch - 1)) != 0) {
283        R128TRACE(("NPOT pitch 0x%x unsupported\n", pitch));
284	return FALSE;
285    }
286
287    if (!R128GetDatatypePict2(pPict->format, tex_cntl_c)) return FALSE;
288
289    bytepp = PICT_FORMAT_BPP(pPict->format) / 8;
290    *tex_cntl_c |= R128_MIP_MAP_DISABLE;
291
292    if (pPict->filter == PictFilterBilinear) {
293        *tex_cntl_c |= R128_MIN_BLEND_LINEAR | R128_MAG_BLEND_LINEAR;
294    } else if (pPict->filter == PictFilterNearest) {
295	*tex_cntl_c |= R128_MIN_BLEND_NEAREST | R128_MAG_BLEND_NEAREST;
296    } else {
297	R128TRACE(("Bad filter 0x%x\n", pPict->filter));
298	return FALSE;
299    }
300
301    if (unit == 0) {
302        shift = 0;
303    } else {
304        shift = 16;
305        *tex_cntl_c |= R128_SEC_SELECT_SEC_ST;
306    }
307
308    l2w = R128MinBits(w) - 1;
309    l2h = R128MinBits(h) - 1;
310    l2p = R128MinBits(pitch / bytepp) - 1;
311
312    if (pPict->repeat && w == 1 && h == 1) {
313        l2p = 0;
314    } else if (pPict->repeat && l2p != l2w) {
315        R128TRACE(("Repeat not supported for pitch != width\n"));
316	return FALSE;
317    }
318
319    l2w = l2p;
320    /* This is required to handle NPOT height */
321    if ((unit == 1) || (unit == 0 && !pPict->repeat && !trying_solid)) l2h++;
322
323    info->state_2d.widths[unit] = 1 << l2w;
324    info->state_2d.heights[unit] = 1 << l2h;
325    *txsize |= l2p << (R128_TEX_PITCH_SHIFT + shift);
326    *txsize |= ((w > h) ? l2w : l2h) << (R128_TEX_SIZE_SHIFT + shift);
327    *txsize |= l2h << (R128_TEX_HEIGHT_SHIFT + shift);
328
329    if (pPict->transform != 0) {
330        info->state_2d.is_transform[unit] = TRUE;
331        info->state_2d.transform[unit] = pPict->transform;
332    } else {
333        info->state_2d.is_transform[unit] = FALSE;
334    }
335
336    return TRUE;
337}
338
339/* The composite preparation commands that are the same every time can
340 * just be written once.
341 */
342#define COMPOSITE_SETUP()				\
343do {							\
344    BEGIN_RING( 10 );					\
345							\
346    OUT_RING_REG(R128_SCALE_3D_CNTL,			\
347		    R128_SCALE_3D_TEXMAP_SHADE |	\
348		    R128_SCALE_PIX_REPLICATE |		\
349		    R128_TEX_CACHE_SPLIT |		\
350		    R128_TEX_MAP_ALPHA_IN_TEXTURE |	\
351		    R128_TEX_CACHE_LINE_SIZE_4QW);	\
352    OUT_RING_REG(R128_SETUP_CNTL,			\
353		    R128_COLOR_SOLID_COLOR |		\
354		    R128_PRIM_TYPE_TRI |		\
355		    R128_TEXTURE_ST_MULT_W |		\
356		    R128_STARTING_VERTEX_1 |		\
357		    R128_ENDING_VERTEX_3 |		\
358		    R128_SUB_PIX_4BITS);		\
359    OUT_RING_REG(R128_PM4_VC_FPU_SETUP,			\
360		    R128_FRONT_DIR_CCW |		\
361		    R128_BACKFACE_CULL |		\
362		    R128_FRONTFACE_SOLID |		\
363		    R128_FPU_COLOR_SOLID |		\
364		    R128_FPU_SUB_PIX_4BITS |		\
365		    R128_FPU_MODE_3D |			\
366		    R128_TRAP_BITS_DISABLE |		\
367		    R128_XFACTOR_2 |			\
368		    R128_YFACTOR_2 |			\
369		    R128_FLAT_SHADE_VERTEX_OGL |	\
370		    R128_FPU_ROUND_TRUNCATE |		\
371		    R128_WM_SEL_8DW);			\
372    OUT_RING_REG(R128_PLANE_3D_MASK_C, 0xffffffff);	\
373    OUT_RING_REG(R128_CONSTANT_COLOR_C, 0xff000000);	\
374							\
375    ADVANCE_RING();					\
376} while(0)
377
378static Bool
379R128CCEPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
380    PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
381{
382    ScreenPtr     pScreen   = pDst->drawable.pScreen;
383    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
384    R128InfoPtr   info      = R128PTR(pScrn);
385    unsigned char *R128MMIO = info->MMIO;
386    RING_LOCALS;
387
388    Bool add_src = FALSE;
389    Bool add_msk = FALSE;
390    uint32_t txsize = 0, prim_tex_cntl_c, sec_tex_cntl_c = 0, dstDatatype;
391    uint32_t src_pitch_offset, dst_pitch_offset, color_factor, in_color_factor, alpha_comb;
392    uint32_t sblend, dblend, blend_cntl, window_offset;
393    int i;
394
395    if (pDstPicture->format == PICT_a8) {
396        if (R128BlendOp[op].dst_alpha) {
397	    R128TRACE(("Can't dst alpha blend A8\n"));
398	    return FALSE;
399        }
400        dstDatatype = R128_DATATYPE_Y8;
401    } else {
402        if (!R128GetDatatypePict1(pDstPicture->format, &dstDatatype)) return FALSE;
403    }
404
405    if (!pSrc) {
406	pSrc = R128SolidPixmap(pScreen, cpu_to_le32(pSrcPicture->pSourcePict->solidFill.color));
407	if (!pSrc) {
408	    R128TRACE(("Failed to create solid scratch pixmap\n"));
409	    return FALSE;
410	}
411	add_src = TRUE;
412    }
413    if (pMaskPicture) {
414        info->state_2d.has_mask = TRUE;
415        if (!pMask) {
416	    pMask = R128SolidPixmap(pScreen, cpu_to_le32(pMaskPicture->pSourcePict->solidFill.color));
417	    if (!pMask) {
418	        if (!pSrcPicture->pDrawable)
419		    pScreen->DestroyPixmap(pSrc);
420		info->state_2d.has_mask = FALSE;
421	        R128TRACE(("Failed to create solid scratch pixmap\n"));
422	        return FALSE;
423	    }
424	    add_msk = TRUE;
425	}
426    } else {
427        info->state_2d.has_mask = FALSE;
428    }
429
430    if (!R128TextureSetup(pSrcPicture, pSrc, 0, &txsize, &prim_tex_cntl_c, (add_src || add_msk))) return FALSE;
431
432    if (pMask != NULL) {
433	info->state_2d.has_mask = TRUE;
434        if (!R128TextureSetup(pMaskPicture, pMask, 1, &txsize, &sec_tex_cntl_c, (add_src || add_msk))) return FALSE;
435    } else {
436	info->state_2d.has_mask = FALSE;
437	info->state_2d.is_transform[1] = FALSE;
438    }
439
440    if (!R128GetPixmapOffsetPitch(pDst, &dst_pitch_offset)) return FALSE;
441    if (!R128GetPixmapOffsetPitch(pSrc, &src_pitch_offset)) return FALSE;
442
443    info->state_2d.in_use = TRUE;
444    if (add_src) info->state_2d.src_pix = pSrc;
445    if (add_msk) info->state_2d.msk_pix = pMask;
446    sblend = R128BlendOp[op].sblend;
447    dblend = R128BlendOp[op].dblend;
448    if (PICT_FORMAT_A(pDstPicture->format) == 0 && R128BlendOp[op].dst_alpha) {
449        if (sblend == R128_ALPHA_BLEND_DSTALPHA)
450	    sblend = R128_ALPHA_BLEND_ONE;
451	else if (sblend == R128_ALPHA_BLEND_INVDSTALPHA)
452	    sblend = R128_ALPHA_BLEND_ZERO;
453    }
454    blend_cntl = (sblend << R128_ALPHA_BLEND_SRC_SHIFT) |
455		 (dblend << R128_ALPHA_BLEND_DST_SHIFT);
456
457    R128CCE_REFRESH( pScrn, info );
458
459    if (!info->state_2d.composite_setup) {
460        COMPOSITE_SETUP();
461	/* DRI and EXA are fighting over control of the texture hardware.
462	 * That means we need to set up the compositing hardware every time
463	 * while a 3D app is running and once after it closes.
464	 */
465	if (!info->have3DWindows)
466	    info->state_2d.composite_setup = TRUE;
467    }
468
469    /* We cannot guarantee that this register will stay zero - DRI needs it too. */
470    if (info->have3DWindows)
471        info->ExaDriver->WaitMarker(pScreen, 0);
472    window_offset = INREG(R128_WINDOW_XY_OFFSET);
473    info->state_2d.x_offset = (window_offset & 0xfff00000) >> R128_WINDOW_X_SHIFT;
474    info->state_2d.y_offset = (window_offset & 0x000fffff) >> R128_WINDOW_Y_SHIFT;
475
476    info->state_2d.dp_gui_master_cntl = (R128_GMC_DST_PITCH_OFFSET_CNTL |
477        R128_GMC_BRUSH_SOLID_COLOR |
478        (dstDatatype >> 8) |
479        R128_GMC_SRC_DATATYPE_COLOR |
480        R128_ROP[3].rop |
481        R128_DP_SRC_SOURCE_MEMORY |
482        R128_GMC_3D_FCN_EN |
483        R128_GMC_CLR_CMP_CNTL_DIS |
484        R128_GMC_AUX_CLIP_DIS |
485        R128_GMC_WR_MSK_DIS);
486    info->state_2d.dp_cntl = (R128_DST_X_LEFT_TO_RIGHT | R128_DST_Y_TOP_TO_BOTTOM);
487    info->state_2d.dp_brush_frgd_clr = 0xffffffff;
488    info->state_2d.dp_brush_bkgd_clr = 0x00000000;
489    info->state_2d.dp_src_frgd_clr = 0xffffffff;
490    info->state_2d.dp_src_bkgd_clr = 0x00000000;
491    info->state_2d.dp_write_mask = 0xffffffff;
492    info->state_2d.dst_pitch_offset = dst_pitch_offset;
493    info->state_2d.src_pitch_offset = src_pitch_offset;
494    info->state_2d.default_sc_bottom_right = (R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX);
495    EmitCCE2DState(pScrn);
496
497    BEGIN_RING( 6 );
498    OUT_RING_REG(R128_MISC_3D_STATE_CNTL_REG,
499        R128_MISC_SCALE_3D_TEXMAP_SHADE |
500        R128_MISC_SCALE_PIX_REPLICATE |
501        R128_ALPHA_COMB_ADD_CLAMP |
502        blend_cntl);
503    OUT_RING_REG(R128_TEX_CNTL_C,
504        R128_TEXMAP_ENABLE |
505        ((pMask != NULL) ? R128_SEC_TEXMAP_ENABLE : 0) |
506        R128_ALPHA_ENABLE |
507        R128_TEX_CACHE_FLUSH);
508    OUT_RING_REG(R128_PC_GUI_CTLSTAT, R128_PC_FLUSH_GUI);
509    ADVANCE_RING();
510
511    /* IN operator: Without a mask, only the first texture unit is enabled.
512     * With a mask, we put the source in the first unit and have it pass
513     * through as input to the 2nd.  The 2nd unit takes the incoming source
514     * pixel and modulates it with either the alpha or each of the channels
515     * in the mask, depending on componentAlpha.
516     */
517    BEGIN_RING( 15 );
518    /* R128_PRIM_TEX_CNTL_C,
519     * R128_PRIM_TEXTURE_COMBINE_CNTL_C,
520     * R128_TEX_SIZE_PITCH_C,
521     * R128_PRIM_TEX_0_OFFSET_C - R128_PRIM_TEX_10_OFFSET_C
522     */
523    OUT_RING(CCE_PACKET0(R128_PRIM_TEX_CNTL_C, 13));
524    OUT_RING(prim_tex_cntl_c);
525
526    /* If this is the only stage and the dest is a8, route the alpha result
527     * to the color (red channel, in particular), too.  Otherwise, be sure
528     * to zero out color channels of an a8 source.
529     */
530    if (pMaskPicture == NULL && pDstPicture->format == PICT_a8)
531        color_factor = R128_COLOR_FACTOR_ALPHA;
532    else if (pSrcPicture->format == PICT_a8)
533        color_factor = R128_COLOR_FACTOR_CONST_COLOR;
534    else
535        color_factor = R128_COLOR_FACTOR_TEX;
536
537    if (PICT_FORMAT_A(pSrcPicture->format) == 0)
538        alpha_comb = R128_COMB_ALPHA_COPY_INP;
539    else
540        alpha_comb = R128_COMB_ALPHA_DIS;
541
542    OUT_RING(R128_COMB_COPY |
543        color_factor |
544        R128_INPUT_FACTOR_INT_COLOR |
545        alpha_comb |
546        R128_ALPHA_FACTOR_TEX_ALPHA |
547        R128_INP_FACTOR_A_CONST_ALPHA);
548    OUT_RING(txsize);
549    /* We could save some output by only writing the offset register that
550     * will actually be used.  On the other hand, this is easy.
551     */
552    for (i = 0; i <= 10; i++)
553        OUT_RING(exaGetPixmapOffset(pSrc));
554    ADVANCE_RING();
555
556    if (pMask != NULL) {
557        BEGIN_RING( 14 );
558	/* R128_SEC_TEX_CNTL_C,
559	 * R128_SEC_TEXTURE_COMBINE_CNTL_C,
560	 * R128_SEC_TEX_0_OFFSET_C - R128_SEC_TEX_10_OFFSET_C
561	 */
562        OUT_RING(CCE_PACKET0(R128_SEC_TEX_CNTL_C, 12));
563        OUT_RING(sec_tex_cntl_c);
564
565        if (pDstPicture->format == PICT_a8) {
566            color_factor = R128_COLOR_FACTOR_ALPHA;
567            in_color_factor = R128_INPUT_FACTOR_PREV_ALPHA;
568        } else if (pMaskPicture->componentAlpha) {
569            color_factor = R128_COLOR_FACTOR_TEX;
570            in_color_factor = R128_INPUT_FACTOR_PREV_COLOR;
571        } else {
572            color_factor = R128_COLOR_FACTOR_ALPHA;
573            in_color_factor = R128_INPUT_FACTOR_PREV_COLOR;
574        }
575
576        OUT_RING(R128_COMB_MODULATE |
577            color_factor |
578            in_color_factor |
579            R128_COMB_ALPHA_MODULATE |
580            R128_ALPHA_FACTOR_TEX_ALPHA |
581            R128_INP_FACTOR_A_PREV_ALPHA);
582        for (i = 0; i <= 10; i++)
583            OUT_RING(exaGetPixmapOffset(pMask));
584	ADVANCE_RING();
585    }
586
587    return TRUE;
588}
589
590typedef union { float f; CARD32 i; } fi_type;
591
592static inline CARD32
593R128FloatAsInt(float val)
594{
595	fi_type fi;
596
597	fi.f = val;
598	return fi.i;
599}
600
601#define VTX_OUT_MASK(_dstX, _dstY, _srcX, _srcY, _maskX, _maskY)			\
602do {											\
603    OUT_RING(R128FloatAsInt((_dstX)));							\
604    OUT_RING(R128FloatAsInt(((float)(_dstY)) + 0.125));					\
605    OUT_RING(R128FloatAsInt(0.0));							\
606    OUT_RING(R128FloatAsInt(1.0));							\
607    OUT_RING(R128FloatAsInt((((float)(_srcX)) + 0.5) / (info->state_2d.widths[0])));	\
608    OUT_RING(R128FloatAsInt((((float)(_srcY)) + 0.5) / (info->state_2d.heights[0])));	\
609    OUT_RING(R128FloatAsInt((((float)(_maskX)) + 0.5) / (info->state_2d.widths[1])));	\
610    OUT_RING(R128FloatAsInt((((float)(_maskY)) + 0.5) / (info->state_2d.heights[1])));	\
611} while (0)
612
613#define VTX_OUT(_dstX, _dstY, _srcX, _srcY)						\
614do {								       			\
615    OUT_RING(R128FloatAsInt((_dstX)));							\
616    OUT_RING(R128FloatAsInt(((float)(_dstY)) + 0.125));					\
617    OUT_RING(R128FloatAsInt(0.0));							\
618    OUT_RING(R128FloatAsInt(1.0));							\
619    OUT_RING(R128FloatAsInt((((float)(_srcX)) + 0.5) / (info->state_2d.widths[0])));	\
620    OUT_RING(R128FloatAsInt((((float)(_srcY)) + 0.5) / (info->state_2d.heights[0])));	\
621} while (0)
622
623static void
624R128CCEComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, int w, int h)
625{
626    ScreenPtr     pScreen   = pDst->drawable.pScreen;
627    ScrnInfoPtr   pScrn     = xf86ScreenToScrn(pScreen);
628    R128InfoPtr   info      = R128PTR(pScrn);
629    RING_LOCALS;
630
631    int srcXend, srcYend, maskXend, maskYend;
632    PictVector v;
633
634    srcXend = srcX + w;
635    srcYend = srcY + h;
636    maskXend = maskX + w;
637    maskYend = maskY + h;
638    if (info->state_2d.is_transform[0]) {
639        v.vector[0] = IntToxFixed(srcX);
640        v.vector[1] = IntToxFixed(srcY);
641        v.vector[2] = xFixed1;
642        PictureTransformPoint(info->state_2d.transform[0], &v);
643        srcX = xFixedToInt(v.vector[0]);
644        srcY = xFixedToInt(v.vector[1]);
645        v.vector[0] = IntToxFixed(srcXend);
646        v.vector[1] = IntToxFixed(srcYend);
647        v.vector[2] = xFixed1;
648        PictureTransformPoint(info->state_2d.transform[0], &v);
649        srcXend = xFixedToInt(v.vector[0]);
650        srcYend = xFixedToInt(v.vector[1]);
651    }
652    if (info->state_2d.is_transform[1]) {
653        v.vector[0] = IntToxFixed(maskX);
654        v.vector[1] = IntToxFixed(maskY);
655        v.vector[2] = xFixed1;
656        PictureTransformPoint(info->state_2d.transform[1], &v);
657        maskX = xFixedToInt(v.vector[0]);
658        maskY = xFixedToInt(v.vector[1]);
659        v.vector[0] = IntToxFixed(maskXend);
660        v.vector[1] = IntToxFixed(maskYend);
661        v.vector[2] = xFixed1;
662        PictureTransformPoint(info->state_2d.transform[1], &v);
663        maskXend = xFixedToInt(v.vector[0]);
664        maskYend = xFixedToInt(v.vector[1]);
665    }
666
667    dstX -= info->state_2d.x_offset;
668    dstY -= info->state_2d.y_offset;
669
670    R128CCE_REFRESH( pScrn, info );
671
672    if (info->state_2d.has_mask) {
673        BEGIN_RING( 3 + 4 * 8 );
674        OUT_RING(CCE_PACKET3(R128_CCE_PACKET3_3D_RNDR_GEN_PRIM, 1 + 4 * 8));
675
676	OUT_RING(R128_CCE_VC_FRMT_RHW |
677            R128_CCE_VC_FRMT_S_T |
678            R128_CCE_VC_FRMT_S2_T2);
679    } else {
680        BEGIN_RING( 3 + 4 * 6 );
681        OUT_RING(CCE_PACKET3(R128_CCE_PACKET3_3D_RNDR_GEN_PRIM, 1 + 4 * 6));
682
683	OUT_RING(R128_CCE_VC_FRMT_RHW |
684            R128_CCE_VC_FRMT_S_T);
685    }
686
687    OUT_RING(R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN |
688        R128_CCE_VC_CNTL_PRIM_WALK_RING |
689        (4 << R128_CCE_VC_CNTL_NUM_SHIFT));
690
691    if (info->state_2d.has_mask) {
692	VTX_OUT_MASK(dstX,     dstY,     srcX,    srcY,    maskX,    maskY);
693	VTX_OUT_MASK(dstX,     dstY + h, srcX,    srcYend, maskX,    maskYend);
694	VTX_OUT_MASK(dstX + w, dstY + h, srcXend, srcYend, maskXend, maskYend);
695	VTX_OUT_MASK(dstX + w, dstY,     srcXend, srcY,    maskXend, maskY);
696    } else {
697	VTX_OUT(dstX,     dstY,     srcX,    srcY);
698	VTX_OUT(dstX,     dstY + h, srcX,    srcYend);
699	VTX_OUT(dstX + w, dstY + h, srcXend, srcYend);
700	VTX_OUT(dstX + w, dstY,     srcXend, srcY);
701    }
702
703    ADVANCE_RING();
704}
705
706#define R128CCEDoneComposite R128Done
707