nv50: minor tweaks to composite
[nouveau] / src / nv50_exa.c
1 /*
2  * Copyright 2007 NVIDIA, Corporation
3  * Copyright 2008 Ben Skeggs
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23
24 #include "nv_include.h"
25
26 #include "nv50_accel.h"
27 #include "nv50_texture.h"
28
29 struct nv50_exa_state {
30         Bool have_mask;
31
32         struct {
33                 PictTransformPtr transform;
34                 float width;
35                 float height;
36         } unit[2];
37 };
38 static struct nv50_exa_state exa_state;
39
40 #define NV50EXA_LOCALS(p)                                              \
41         ScrnInfoPtr pScrn = xf86Screens[(p)->drawable.pScreen->myNum]; \
42         NVPtr pNv = NVPTR(pScrn);                                      \
43         struct nouveau_channel *chan = pNv->chan; (void)chan;          \
44         struct nouveau_grobj *eng2d = pNv->Nv2D; (void)eng2d;          \
45         struct nouveau_grobj *tesla = pNv->Nv3D; (void)tesla;          \
46         struct nv50_exa_state *state = &exa_state; (void)state
47
48 #define BF(f) (NV50TCL_BLEND_FUNC_SRC_RGB_##f | 0x4000)
49
50 struct nv50_blend_op {
51         unsigned src_alpha;
52         unsigned dst_alpha;
53         unsigned src_blend;
54         unsigned dst_blend;
55 };
56
57 static struct nv50_blend_op
58 NV50EXABlendOp[] = {
59 /* Clear       */ { 0, 0, BF(               ZERO), BF(               ZERO) },
60 /* Src         */ { 0, 0, BF(                ONE), BF(               ZERO) },
61 /* Dst         */ { 0, 0, BF(               ZERO), BF(                ONE) },
62 /* Over        */ { 1, 0, BF(                ONE), BF(ONE_MINUS_SRC_ALPHA) },
63 /* OverReverse */ { 0, 1, BF(ONE_MINUS_DST_ALPHA), BF(                ONE) },
64 /* In          */ { 0, 1, BF(          DST_ALPHA), BF(               ZERO) },
65 /* InReverse   */ { 1, 0, BF(               ZERO), BF(          SRC_ALPHA) },
66 /* Out         */ { 0, 1, BF(ONE_MINUS_DST_ALPHA), BF(               ZERO) },
67 /* OutReverse  */ { 1, 0, BF(               ZERO), BF(ONE_MINUS_SRC_ALPHA) },
68 /* Atop        */ { 1, 1, BF(          DST_ALPHA), BF(ONE_MINUS_SRC_ALPHA) },
69 /* AtopReverse */ { 1, 1, BF(ONE_MINUS_DST_ALPHA), BF(          SRC_ALPHA) },
70 /* Xor         */ { 1, 1, BF(ONE_MINUS_DST_ALPHA), BF(ONE_MINUS_SRC_ALPHA) },
71 /* Add         */ { 0, 0, BF(                ONE), BF(                ONE) },
72 };
73
74 static Bool
75 NV50EXA2DSurfaceFormat(PixmapPtr ppix, uint32_t *fmt)
76 {
77         NV50EXA_LOCALS(ppix);
78
79         switch (ppix->drawable.depth) {
80         case 8 : *fmt = NV50_2D_SRC_FORMAT_8BPP; break;
81         case 15: *fmt = NV50_2D_SRC_FORMAT_15BPP; break;
82         case 16: *fmt = NV50_2D_SRC_FORMAT_16BPP; break;
83         case 24: *fmt = NV50_2D_SRC_FORMAT_24BPP; break;
84         case 32: *fmt = NV50_2D_SRC_FORMAT_32BPP; break;
85         default:
86                  xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
87                             "Unknown surface format for bpp=%d\n",
88                             ppix->drawable.depth);
89                  return FALSE;
90         }
91
92         return TRUE;
93 }
94
95 static void NV50EXASetClip(PixmapPtr ppix, int x, int y, int w, int h)
96 {
97         NV50EXA_LOCALS(ppix);
98
99         BEGIN_RING(chan, eng2d, NV50_2D_CLIP_X, 4);
100         OUT_RING  (chan, x);
101         OUT_RING  (chan, y);
102         OUT_RING  (chan, w);
103         OUT_RING  (chan, h);
104 }
105
106 static Bool
107 NV50EXAAcquireSurface2D(PixmapPtr ppix, int is_src)
108 {
109         NV50EXA_LOCALS(ppix);
110         int mthd = is_src ? NV50_2D_SRC_FORMAT : NV50_2D_DST_FORMAT;
111         uint32_t fmt, bo_flags;
112
113         if (!NV50EXA2DSurfaceFormat(ppix, &fmt))
114                 return FALSE;
115
116         bo_flags  = NOUVEAU_BO_VRAM;
117         bo_flags |= is_src ? NOUVEAU_BO_RD : NOUVEAU_BO_WR;
118
119         if (exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase) {
120                 BEGIN_RING(chan, eng2d, mthd, 2);
121                 OUT_RING  (chan, fmt);
122                 OUT_RING  (chan, 1);
123                 BEGIN_RING(chan, eng2d, mthd + 0x14, 1);
124                 OUT_RING  (chan, (uint32_t)exaGetPixmapPitch(ppix));
125         } else {
126                 BEGIN_RING(chan, eng2d, mthd, 5);
127                 OUT_RING  (chan, fmt);
128                 OUT_RING  (chan, 0);
129                 OUT_RING  (chan, 0);
130                 OUT_RING  (chan, 1);
131                 OUT_RING  (chan, 0);
132         }
133
134         BEGIN_RING(chan, eng2d, mthd + 0x18, 4);
135         OUT_RING  (chan, ppix->drawable.width);
136         OUT_RING  (chan, ppix->drawable.height);
137         OUT_PIXMAPh(chan, ppix, 0, bo_flags);
138         OUT_PIXMAPl(chan, ppix, 0, bo_flags);
139
140         if (is_src == 0)
141                 NV50EXASetClip(ppix, 0, 0, ppix->drawable.width, ppix->drawable.height);
142
143         return TRUE;
144 }
145
146 static void
147 NV50EXASetPattern(PixmapPtr pdpix, int col0, int col1, int pat0, int pat1)
148 {
149         NV50EXA_LOCALS(pdpix);
150
151         BEGIN_RING(chan, eng2d, NV50_2D_PATTERN_COLOR(0), 4);
152         OUT_RING  (chan, col0);
153         OUT_RING  (chan, col1);
154         OUT_RING  (chan, pat0);
155         OUT_RING  (chan, pat1);
156 }
157
158 extern const int NVCopyROP[16];
159 static void
160 NV50EXASetROP(PixmapPtr pdpix, int alu, Pixel planemask)
161 {
162         NV50EXA_LOCALS(pdpix);
163         int rop = NVCopyROP[alu];
164
165         BEGIN_RING(chan, eng2d, NV50_2D_OPERATION, 1);
166         if (alu == GXcopy && planemask == ~0) {
167                 OUT_RING  (chan, NV50_2D_OPERATION_SRCCOPY);
168                 return;
169         } else {
170                 OUT_RING  (chan, NV50_2D_OPERATION_SRCCOPY_PREMULT);
171         }
172
173         BEGIN_RING(chan, eng2d, NV50_2D_PATTERN_FORMAT, 2);
174         switch (pdpix->drawable.depth) {
175                 case  8: OUT_RING  (chan, 3); break;
176                 case 15: OUT_RING  (chan, 1); break;
177                 case 16: OUT_RING  (chan, 0); break;
178                 case 24:
179                 case 32:
180                 default:
181                          OUT_RING  (chan, 2);
182                          break;
183         }
184         OUT_RING  (chan, 1);
185
186         /* I observed incorrect rendering and found this in a fifo trace. */
187         /* It fixed the one test-case i had, so i'm happy. */
188         if (pdpix->drawable.depth == 32)
189                 rop &= 0xF0;
190
191         /* There are 16 alu's. pNv->currentRop stores: */
192         /* 0-15: planemask == ~0 && bpp != 32 */
193         /* 16-31: planemask == ~0 && bpp == 32 */
194         /* 32-47: planemask != ~0 */
195         if (planemask != ~0) {
196                 NV50EXASetPattern(pdpix, 0, planemask, ~0, ~0);
197                 rop = (rop & 0xf0) | 0x0a;
198
199                 if (pNv->currentRop != (alu + 32)) {
200                         BEGIN_RING(chan, eng2d, NV50_2D_ROP, 1);
201                         OUT_RING  (chan, rop);
202                         pNv->currentRop = alu + 32;
203                 }
204         } else {
205                 /* This makes no sense for planemask != ~0, as that already masks with 0xA. */
206                 if (pdpix->drawable.depth == 32)
207                         alu += 16;
208
209                 if (pNv->currentRop != alu) {
210                         if (pNv->currentRop >= 32)
211                                 NV50EXASetPattern(pdpix, ~0, ~0, ~0, ~0);
212
213                         BEGIN_RING(chan, eng2d, NV50_2D_ROP, 1);
214                         OUT_RING  (chan, rop);
215                         pNv->currentRop = alu;
216                 }
217         }
218 }
219
220 Bool
221 NV50EXAPrepareSolid(PixmapPtr pdpix, int alu, Pixel planemask, Pixel fg)
222 {
223         NV50EXA_LOCALS(pdpix);
224         uint32_t fmt;
225
226         planemask |= ~0 << pdpix->drawable.bitsPerPixel;
227
228         if (!NV50EXA2DSurfaceFormat(pdpix, &fmt))
229                 NOUVEAU_FALLBACK("rect format\n");
230         if (!NV50EXAAcquireSurface2D(pdpix, 0))
231                 NOUVEAU_FALLBACK("dest pixmap\n");
232         NV50EXASetROP(pdpix, alu, planemask);
233
234         BEGIN_RING(chan, eng2d, 0x580, 3);
235         OUT_RING  (chan, 4);
236         OUT_RING  (chan, fmt);
237         OUT_RING  (chan, fg);
238
239         return TRUE;
240 }
241
242 void
243 NV50EXASolid(PixmapPtr pdpix, int x1, int y1, int x2, int y2)
244 {
245         NV50EXA_LOCALS(pdpix);
246
247         BEGIN_RING(chan, eng2d, NV50_2D_RECT_X1, 4);
248         OUT_RING  (chan, x1);
249         OUT_RING  (chan, y1);
250         OUT_RING  (chan, x2);
251         OUT_RING  (chan, y2);
252
253         if((x2 - x1) * (y2 - y1) >= 512)
254                 FIRE_RING (chan);
255 }
256
257 void
258 NV50EXADoneSolid(PixmapPtr pdpix)
259 {
260 }
261
262 Bool
263 NV50EXAPrepareCopy(PixmapPtr pspix, PixmapPtr pdpix, int dx, int dy,
264                    int alu, Pixel planemask)
265 {
266         NV50EXA_LOCALS(pdpix);
267
268         planemask |= ~0 << pdpix->drawable.bitsPerPixel;
269
270         if (!NV50EXAAcquireSurface2D(pspix, 1))
271                 NOUVEAU_FALLBACK("src pixmap\n");
272         if (!NV50EXAAcquireSurface2D(pdpix, 0))
273                 NOUVEAU_FALLBACK("dest pixmap\n");
274         NV50EXASetROP(pdpix, alu, planemask);
275
276         return TRUE;
277 }
278
279 void
280 NV50EXACopy(PixmapPtr pdpix, int srcX , int srcY,
281                              int dstX , int dstY,
282                              int width, int height)
283 {
284         NV50EXA_LOCALS(pdpix);
285
286         BEGIN_RING(chan, eng2d, 0x0110, 1);
287         OUT_RING  (chan, 0);
288         BEGIN_RING(chan, eng2d, 0x088c, 1);
289         OUT_RING  (chan, 0);
290         BEGIN_RING(chan, eng2d, NV50_2D_BLIT_DST_X, 12);
291         OUT_RING  (chan, dstX);
292         OUT_RING  (chan, dstY);
293         OUT_RING  (chan, width);
294         OUT_RING  (chan, height);
295         OUT_RING  (chan, 0);
296         OUT_RING  (chan, 1);
297         OUT_RING  (chan, 0);
298         OUT_RING  (chan, 1);
299         OUT_RING  (chan, 0);
300         OUT_RING  (chan, srcX);
301         OUT_RING  (chan, 0);
302         OUT_RING  (chan, srcY);
303
304         if(width * height >= 512)
305                 FIRE_RING (chan);
306 }
307
308 void
309 NV50EXADoneCopy(PixmapPtr pdpix)
310 {
311 }
312
313 Bool
314 NV50EXAUploadSIFC(const char *src, int src_pitch,
315                   PixmapPtr pdpix, int x, int y, int w, int h, int cpp)
316 {
317         NV50EXA_LOCALS(pdpix);
318         int line_dwords = (w * cpp + 3) / 4;
319         uint32_t sifc_fmt;
320
321         if (!NV50EXA2DSurfaceFormat(pdpix, &sifc_fmt))
322                 NOUVEAU_FALLBACK("hostdata format\n");
323         if (!NV50EXAAcquireSurface2D(pdpix, 0))
324                 NOUVEAU_FALLBACK("dest pixmap\n");
325
326         /* If the pitch isn't aligned to a dword, then you can get corruption at the end of a line. */
327         NV50EXASetClip(pdpix, x, y, w, h);
328
329         BEGIN_RING(chan, eng2d, NV50_2D_OPERATION, 1);
330         OUT_RING  (chan, NV50_2D_OPERATION_SRCCOPY);
331         BEGIN_RING(chan, eng2d, NV50_2D_SIFC_UNK0800, 2);
332         OUT_RING  (chan, 0);
333         OUT_RING  (chan, sifc_fmt);
334         BEGIN_RING(chan, eng2d, NV50_2D_SIFC_WIDTH, 10);
335         OUT_RING  (chan, (line_dwords * 4) / cpp);
336         OUT_RING  (chan, h);
337         OUT_RING  (chan, 0);
338         OUT_RING  (chan, 1);
339         OUT_RING  (chan, 0);
340         OUT_RING  (chan, 1);
341         OUT_RING  (chan, 0);
342         OUT_RING  (chan, x);
343         OUT_RING  (chan, 0);
344         OUT_RING  (chan, y);
345
346         while (h--) {
347                 int count = line_dwords;
348                 const char *p = src;
349
350                 while(count) {
351                         int size = count > 1792 ? 1792 : count;
352
353                         BEGIN_RING(chan, eng2d,
354                                          NV50_2D_SIFC_DATA | 0x40000000, size);
355                         OUT_RINGp (chan, p, size);
356
357                         p += size * cpp;
358                         count -= size;
359                 }
360
361                 src += src_pitch;
362         }
363
364         return TRUE;
365 }
366
367 static Bool
368 NV50EXACheckRenderTarget(PicturePtr ppict)
369 {
370         if (ppict->pDrawable->width > 8192 ||
371             ppict->pDrawable->height > 8192)
372                 NOUVEAU_FALLBACK("render target dimensions exceeded %dx%d\n",
373                                  ppict->pDrawable->width,
374                                  ppict->pDrawable->height);
375
376         switch (ppict->format) {
377         case PICT_a8r8g8b8:
378         case PICT_x8r8g8b8:
379         case PICT_r5g6b5:
380         case PICT_a8:
381                 break;
382         default:
383                 NOUVEAU_FALLBACK("picture format 0x%08x\n", ppict->format);
384         }
385
386         return TRUE;
387 }
388
389 static Bool
390 NV50EXARenderTarget(PixmapPtr ppix, PicturePtr ppict)
391 {
392         NV50EXA_LOCALS(ppix);
393         unsigned format;
394
395         /*XXX: Scanout buffer not tiled, someone needs to figure it out */
396         if (exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase)
397                 NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
398
399         switch (ppict->format) {
400         case PICT_a8r8g8b8: format = NV50TCL_RT_FORMAT_32BPP; break;
401         case PICT_x8r8g8b8: format = NV50TCL_RT_FORMAT_24BPP; break;
402         case PICT_r5g6b5  : format = NV50TCL_RT_FORMAT_16BPP; break;
403         case PICT_a8      : format = NV50TCL_RT_FORMAT_8BPP; break;
404         default:
405                 NOUVEAU_FALLBACK("invalid picture format\n");
406         }
407
408         BEGIN_RING(chan, tesla, NV50TCL_RT_ADDRESS_HIGH(0), 5);
409         OUT_PIXMAPh(chan, ppix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
410         OUT_PIXMAPl(chan, ppix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
411         OUT_RING  (chan, format);
412         OUT_RING  (chan, 0);
413         OUT_RING  (chan, 0x00000000);
414         BEGIN_RING(chan, tesla, NV50TCL_RT_HORIZ(0), 2);
415         OUT_RING  (chan, ppix->drawable.width);
416         OUT_RING  (chan, ppix->drawable.height);
417         BEGIN_RING(chan, tesla, 0x1224, 1);
418         OUT_RING  (chan, 0x00000001);
419
420         return TRUE;
421 }
422
423 static Bool
424 NV50EXACheckTexture(PicturePtr ppict)
425 {
426         if (ppict->pDrawable->width > 8192 ||
427             ppict->pDrawable->height > 8192)
428                 NOUVEAU_FALLBACK("texture dimensions exceeded %dx%d\n",
429                                  ppict->pDrawable->width,
430                                  ppict->pDrawable->height);
431
432         switch (ppict->format) {
433         case PICT_a8r8g8b8:
434         case PICT_a8b8g8r8:
435         case PICT_x8r8g8b8:
436         case PICT_x8b8g8r8:
437         case PICT_r5g6b5:
438         case PICT_a8:
439                 break;
440         default:
441                 NOUVEAU_FALLBACK("picture format 0x%08x\n", ppict->format);
442         }
443
444         switch (ppict->filter) {
445         case PictFilterNearest:
446         case PictFilterBilinear:
447                 break;
448         default:
449                 NOUVEAU_FALLBACK("picture filter %d\n", ppict->filter);
450         }
451
452         return TRUE;
453 }
454
455 static Bool
456 NV50EXATexture(PixmapPtr ppix, PicturePtr ppict, unsigned unit)
457 {
458         NV50EXA_LOCALS(ppix);
459
460         /*XXX: Scanout buffer not tiled, someone needs to figure it out */
461         if (exaGetPixmapOffset(ppix) < pNv->EXADriverPtr->offScreenBase)
462                 NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
463
464         BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 1);
465         OUT_RING  (chan, CB_TIC | ((unit * 8) << NV50TCL_CB_ADDR_ID_SHIFT));
466         BEGIN_RING(chan, tesla, NV50TCL_CB_DATA(0) | 0x40000000, 8);
467         switch (ppict->format) {
468         case PICT_a8r8g8b8:
469                 OUT_RING  (chan, NV50TIC_0_0_MAPA_C3 | NV50TIC_0_0_TYPEA_UNORM |
470                          NV50TIC_0_0_MAPR_C0 | NV50TIC_0_0_TYPER_UNORM |
471                          NV50TIC_0_0_MAPG_C1 | NV50TIC_0_0_TYPEB_UNORM |
472                          NV50TIC_0_0_MAPB_C2 | NV50TIC_0_0_TYPEG_UNORM |
473                          NV50TIC_0_0_FMT_8_8_8_8);
474                 break;
475         case PICT_a8b8g8r8:
476                 OUT_RING  (chan, NV50TIC_0_0_MAPA_C3 | NV50TIC_0_0_TYPEA_UNORM |
477                          NV50TIC_0_0_MAPR_C2 | NV50TIC_0_0_TYPER_UNORM |
478                          NV50TIC_0_0_MAPG_C1 | NV50TIC_0_0_TYPEB_UNORM |
479                          NV50TIC_0_0_MAPB_C0 | NV50TIC_0_0_TYPEG_UNORM |
480                          NV50TIC_0_0_FMT_8_8_8_8);
481                 break;
482         case PICT_x8r8g8b8:
483                 OUT_RING  (chan, NV50TIC_0_0_MAPA_ONE | NV50TIC_0_0_TYPEA_UNORM |
484                          NV50TIC_0_0_MAPR_C0 | NV50TIC_0_0_TYPER_UNORM |
485                          NV50TIC_0_0_MAPG_C1 | NV50TIC_0_0_TYPEB_UNORM |
486                          NV50TIC_0_0_MAPB_C2 | NV50TIC_0_0_TYPEG_UNORM |
487                          NV50TIC_0_0_FMT_8_8_8_8);
488                 break;
489         case PICT_x8b8g8r8:
490                 OUT_RING  (chan, NV50TIC_0_0_MAPA_ONE | NV50TIC_0_0_TYPEA_UNORM |
491                          NV50TIC_0_0_MAPR_C2 | NV50TIC_0_0_TYPER_UNORM |
492                          NV50TIC_0_0_MAPG_C1 | NV50TIC_0_0_TYPEB_UNORM |
493                          NV50TIC_0_0_MAPB_C0 | NV50TIC_0_0_TYPEG_UNORM |
494                          NV50TIC_0_0_FMT_8_8_8_8);
495                 break;
496         case PICT_r5g6b5:
497                 OUT_RING  (chan, NV50TIC_0_0_MAPA_ONE | NV50TIC_0_0_TYPEA_UNORM |
498                          NV50TIC_0_0_MAPR_C0 | NV50TIC_0_0_TYPER_UNORM |
499                          NV50TIC_0_0_MAPG_C1 | NV50TIC_0_0_TYPEB_UNORM |
500                          NV50TIC_0_0_MAPB_C2 | NV50TIC_0_0_TYPEG_UNORM |
501                          NV50TIC_0_0_FMT_5_6_5);
502                 break;
503         case PICT_a8:
504                 OUT_RING  (chan, NV50TIC_0_0_MAPA_C0 | NV50TIC_0_0_TYPEA_UNORM |
505                          NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM |
506                          NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEB_UNORM |
507                          NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEG_UNORM |
508                          NV50TIC_0_0_FMT_8);
509                 break;
510         default:
511                 NOUVEAU_FALLBACK("invalid picture format, this SHOULD NOT HAPPEN. Expect trouble.\n");
512         }
513         OUT_PIXMAPl(chan, ppix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
514         OUT_RING  (chan, 0xd0005000);
515         OUT_RING  (chan, 0x00300000);
516         OUT_RING  (chan, ppix->drawable.width);
517         OUT_RING  (chan, (1 << NV50TIC_0_5_DEPTH_SHIFT) | ppix->drawable.height);
518         OUT_RING  (chan, 0x03000000);
519         OUT_PIXMAPh(chan, ppix, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
520
521         BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 1);
522         OUT_RING  (chan, CB_TSC | ((unit * 8) << NV50TCL_CB_ADDR_ID_SHIFT));
523         BEGIN_RING(chan, tesla, NV50TCL_CB_DATA(0) | 0x40000000, 8);
524         if (ppict->repeat) {
525                 switch (ppict->repeatType) {
526                 case RepeatPad:
527                         OUT_RING  (chan, NV50TSC_1_0_WRAPS_CLAMP |
528                                  NV50TSC_1_0_WRAPT_CLAMP |
529                                  NV50TSC_1_0_WRAPR_CLAMP | 0x00024000);
530                         break;
531                 case RepeatReflect:
532                         OUT_RING  (chan, NV50TSC_1_0_WRAPS_MIRROR_REPEAT |
533                                  NV50TSC_1_0_WRAPT_MIRROR_REPEAT |
534                                  NV50TSC_1_0_WRAPR_MIRROR_REPEAT | 0x00024000);
535                         break;
536                 case RepeatNormal:
537                 default:
538                         OUT_RING  (chan, NV50TSC_1_0_WRAPS_REPEAT |
539                                  NV50TSC_1_0_WRAPT_REPEAT |
540                                  NV50TSC_1_0_WRAPR_REPEAT | 0x00024000);
541                         break;
542                 }
543         } else {
544                 OUT_RING  (chan, NV50TSC_1_0_WRAPS_CLAMP_TO_BORDER |
545                          NV50TSC_1_0_WRAPT_CLAMP_TO_BORDER |
546                          NV50TSC_1_0_WRAPR_CLAMP_TO_BORDER | 0x00024000);
547         }
548         if (ppict->filter == PictFilterBilinear) {
549                 OUT_RING  (chan, NV50TSC_1_1_MAGF_LINEAR |
550                          NV50TSC_1_1_MINF_LINEAR |
551                          NV50TSC_1_1_MIPF_NONE);
552         } else {
553                 OUT_RING  (chan, NV50TSC_1_1_MAGF_NEAREST |
554                          NV50TSC_1_1_MINF_NEAREST |
555                          NV50TSC_1_1_MIPF_NONE);
556         }
557         OUT_RING  (chan, 0x00000000);
558         OUT_RING  (chan, 0x00000000);
559         OUT_RING  (chan, 0x00000000);
560         OUT_RING  (chan, 0x00000000);
561         OUT_RING  (chan, 0x00000000);
562         OUT_RING  (chan, 0x00000000);
563
564         state->unit[unit].width = ppix->drawable.width;
565         state->unit[unit].height = ppix->drawable.height;
566         state->unit[unit].transform = ppict->transform;
567         return TRUE;
568 }
569
570 static Bool
571 NV50EXACheckBlend(int op)
572 {
573         if (op > PictOpAdd)
574                 NOUVEAU_FALLBACK("unsupported blend op %d\n", op);
575         return TRUE;
576 }
577
578 static void
579 NV50EXABlend(PixmapPtr ppix, PicturePtr ppict, int op, int component_alpha)
580 {
581         NV50EXA_LOCALS(ppix);
582         struct nv50_blend_op *b = &NV50EXABlendOp[op];
583         unsigned sblend = b->src_blend;
584         unsigned dblend = b->dst_blend;
585
586         if (b->dst_alpha) {
587                 if (!PICT_FORMAT_A(ppict->format)) {
588                         if (sblend == BF(DST_ALPHA))
589                                 sblend = BF(ONE);
590                         else
591                         if (sblend == BF(ONE_MINUS_DST_ALPHA))
592                                 sblend = BF(ZERO);
593                 } else
594                 if (ppict->format == PICT_a8) {
595                         if (sblend == BF(DST_ALPHA))
596                                 sblend = BF(DST_COLOR);
597                         else
598                         if (sblend == BF(ONE_MINUS_DST_ALPHA))
599                                 sblend = BF(ONE_MINUS_DST_COLOR);
600                 }
601         }
602
603         if (b->src_alpha && (component_alpha || ppict->format == PICT_a8)) {
604                 if (dblend == BF(SRC_ALPHA))
605                         dblend = BF(SRC_COLOR);
606                 else
607                 if (dblend == BF(ONE_MINUS_SRC_ALPHA))
608                         dblend = BF(ONE_MINUS_SRC_COLOR);
609         }
610
611         if (sblend == BF(ONE) && dblend == BF(ZERO)) {
612                 BEGIN_RING(chan, tesla, NV50TCL_BLEND_ENABLE(0), 1);
613                 OUT_RING  (chan, 0);
614         } else {
615                 BEGIN_RING(chan, tesla, NV50TCL_BLEND_ENABLE(0), 1);
616                 OUT_RING  (chan, 1);
617                 BEGIN_RING(chan, tesla, NV50TCL_BLEND_EQUATION_RGB, 5);
618                 OUT_RING  (chan, NV50TCL_BLEND_EQUATION_RGB_FUNC_ADD);
619                 OUT_RING  (chan, sblend);
620                 OUT_RING  (chan, dblend);
621                 OUT_RING  (chan, NV50TCL_BLEND_EQUATION_ALPHA_FUNC_ADD);
622                 OUT_RING  (chan, sblend);
623                 BEGIN_RING(chan, tesla, NV50TCL_BLEND_FUNC_DST_ALPHA, 1);
624                 OUT_RING  (chan, dblend);
625         }
626 }
627
628 Bool
629 NV50EXACheckComposite(int op,
630                       PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict)
631 {
632         if (!NV50EXACheckBlend(op))
633                 NOUVEAU_FALLBACK("blend not supported\n");
634
635         if (!NV50EXACheckRenderTarget(pdpict))
636                 NOUVEAU_FALLBACK("render target invalid\n");
637
638         if (!NV50EXACheckTexture(pspict))
639                 NOUVEAU_FALLBACK("src picture invalid\n");
640
641         if (pmpict) {
642                 if (pmpict->componentAlpha &&
643                     PICT_FORMAT_RGB(pmpict->format) &&
644                     NV50EXABlendOp[op].src_alpha &&
645                     NV50EXABlendOp[op].src_blend != BF(ZERO))
646                         NOUVEAU_FALLBACK("component-alpha not supported\n");
647
648                 if (!NV50EXACheckTexture(pmpict))
649                         NOUVEAU_FALLBACK("mask picture invalid\n");
650         }
651
652         return TRUE;
653 }
654
655 Bool
656 NV50EXAPrepareComposite(int op,
657                         PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict,
658                         PixmapPtr pspix, PixmapPtr pmpix, PixmapPtr pdpix)
659 {
660         NV50EXA_LOCALS(pspix);
661
662         BEGIN_RING(chan, eng2d, 0x0110, 1);
663         OUT_RING  (chan, 0);
664
665         if (!NV50EXARenderTarget(pdpix, pdpict))
666                 NOUVEAU_FALLBACK("render target invalid\n");
667
668         NV50EXABlend(pdpix, pdpict, op, pmpict && pmpict->componentAlpha &&
669                      PICT_FORMAT_RGB(pmpict->format));
670
671         if (pmpict) {
672                 if (!NV50EXATexture(pspix, pspict, 0))
673                         NOUVEAU_FALLBACK("src picture invalid\n");
674                 if (!NV50EXATexture(pmpix, pmpict, 1))
675                         NOUVEAU_FALLBACK("mask picture invalid\n");
676                 state->have_mask = TRUE;
677
678                 BEGIN_RING(chan, tesla, NV50TCL_FP_START_ID, 1);
679                 if (pdpict->format == PICT_a8) {
680                         OUT_RING  (chan, PFP_C_A8);
681                 } else {
682                         if (pmpict->componentAlpha &&
683                             PICT_FORMAT_RGB(pmpict->format)) {
684                                 if (NV50EXABlendOp[op].src_alpha)
685                                         OUT_RING  (chan, PFP_CCASA);
686                                 else
687                                         OUT_RING  (chan, PFP_CCA);
688                         } else {
689                                 OUT_RING  (chan, PFP_C);
690                         }
691                 }
692         } else {
693                 if (!NV50EXATexture(pspix, pspict, 0))
694                         NOUVEAU_FALLBACK("src picture invalid\n");
695                 state->have_mask = FALSE;
696
697                 BEGIN_RING(chan, tesla, NV50TCL_FP_START_ID, 1);
698                 if (pdpict->format == PICT_a8)
699                         OUT_RING  (chan, PFP_S_A8);
700                 else
701                         OUT_RING  (chan, PFP_S);
702         }
703
704         BEGIN_RING(chan, tesla, 0x1334, 1);
705         OUT_RING  (chan, 0);
706
707         BEGIN_RING(chan, tesla, 0x1458, 1);
708         OUT_RING  (chan, 1);
709         BEGIN_RING(chan, tesla, 0x1458, 1);
710         OUT_RING  (chan, 0x203);
711
712         return TRUE;
713 }
714
715 #define xFixedToFloat(v) \
716         ((float)xFixedToInt((v)) + ((float)xFixedFrac(v) / 65536.0))
717 static inline void
718 NV50EXATransform(PictTransformPtr t, int x, int y, float sx, float sy,
719                  float *x_ret, float *y_ret)
720 {
721         if (t) {
722                 PictVector v;
723
724                 v.vector[0] = IntToxFixed(x);
725                 v.vector[1] = IntToxFixed(y);
726                 v.vector[2] = xFixed1;
727                 PictureTransformPoint(t, &v);
728                 *x_ret = xFixedToFloat(v.vector[0]) / sx;
729                 *y_ret = xFixedToFloat(v.vector[1]) / sy;
730         } else {
731                 *x_ret = (float)x / sx;
732                 *y_ret = (float)y / sy;
733         }
734 }
735
736 void
737 NV50EXAComposite(PixmapPtr pdpix, int sx, int sy, int mx, int my,
738                  int dx, int dy, int w, int h)
739 {
740         NV50EXA_LOCALS(pdpix);
741         float sX0, sX1, sX2, sX3, sY0, sY1, sY2, sY3;
742         unsigned dX0 = dx, dX1 = dx + w, dY0 = dy, dY1 = dy + h;
743
744         NV50EXATransform(state->unit[0].transform, sx, sy,
745                          state->unit[0].width, state->unit[0].height,
746                          &sX0, &sY0);
747         NV50EXATransform(state->unit[0].transform, sx + w, sy,
748                          state->unit[0].width, state->unit[0].height,
749                          &sX1, &sY1);
750         NV50EXATransform(state->unit[0].transform, sx + w, sy + h,
751                          state->unit[0].width, state->unit[0].height,
752                          &sX2, &sY2);
753         NV50EXATransform(state->unit[0].transform, sx, sy + h,
754                          state->unit[0].width, state->unit[0].height,
755                          &sX3, &sY3);
756
757         BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
758         OUT_RING  (chan, NV50TCL_VERTEX_BEGIN_QUADS);
759         if (state->have_mask) {
760                 float mX0, mX1, mX2, mX3, mY0, mY1, mY2, mY3;
761
762                 NV50EXATransform(state->unit[1].transform, mx, my,
763                                  state->unit[1].width, state->unit[1].height,
764                                  &mX0, &mY0);
765                 NV50EXATransform(state->unit[1].transform, mx + w, my,
766                                  state->unit[1].width, state->unit[1].height,
767                                  &mX1, &mY1);
768                 NV50EXATransform(state->unit[1].transform, mx + w, my + h,
769                                  state->unit[1].width, state->unit[1].height,
770                                  &mX2, &mY2);
771                 NV50EXATransform(state->unit[1].transform, mx, my + h,
772                                  state->unit[1].width, state->unit[1].height,
773                                  &mX3, &mY3);
774
775                 VTX2s(pNv, sX0, sY0, mX0, mY0, dX0, dY0);
776                 VTX2s(pNv, sX1, sY1, mX1, mY1, dX1, dY0);
777                 VTX2s(pNv, sX2, sY2, mX2, mY2, dX1, dY1);
778                 VTX2s(pNv, sX3, sY3, mX3, mY3, dX0, dY1);
779         } else {
780                 VTX1s(pNv, sX0, sY0, dX0, dY0);
781                 VTX1s(pNv, sX1, sY1, dX1, dY0);
782                 VTX1s(pNv, sX2, sY2, dX1, dY1);
783                 VTX1s(pNv, sX3, sY3, dX0, dY1);
784         }
785         BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
786         OUT_RING  (chan, 0);
787 }
788
789 void
790 NV50EXADoneComposite(PixmapPtr pdpix)
791 {
792 }
793