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