Hint added.
[AROS.git] / workbench / hidds / nouveau / xf86-video-nouveau / nvc0_exa.c
blob6302b56e4388c8b2dc73fa12bcaa72933f9b465f
1 /*
2 * Copyright 2007 NVIDIA, Corporation
3 * Copyright 2008 Ben Skeggs
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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.
24 #include "nv_include.h"
25 #include "nv_rop.h"
26 #include "nvc0_accel.h"
27 #include "nv50_texture.h"
29 #define NOUVEAU_BO(a, b, c) (NOUVEAU_BO_##a | NOUVEAU_BO_##b | NOUVEAU_BO_##c)
31 #if !defined(__AROS__)
32 Bool
33 NVC0AccelDownloadM2MF(PixmapPtr pspix, int x, int y, int w, int h,
34 char *dst, unsigned dst_pitch)
36 ScrnInfoPtr pScrn = xf86Screens[pspix->drawable.pScreen->myNum];
37 #else
38 Bool
39 NVC0AccelDownloadM2MF(PixmapPtr pspix, int x, int y, int w, int h,
40 char *dst, unsigned dst_pitch,
41 HIDDT_StdPixFmt dstPixFmt, OOP_Class *cl, OOP_Object *o)
43 ScrnInfoPtr pScrn = globalcarddataptr;
44 #endif
45 NVPtr pNv = NVPTR(pScrn);
46 struct nouveau_channel *chan = pNv->chan;
47 struct nouveau_bo *bo = nouveau_pixmap_bo(pspix);
48 struct nouveau_grobj *m2mf = pNv->NvMemFormat;
49 #if !defined(__AROS__)
50 const int cpp = pspix->drawable.bitsPerPixel / 8;
51 const int line_len = w * cpp;
52 const int line_limit = (128 << 10) / line_len;
53 unsigned src_offset = 0, src_pitch = 0, tiled = 1;
54 #else
55 const int cpp = pspix->depth > 16 ? 4 : 2;
56 const int line_len = w * cpp;
57 const int line_limit = pNv->GART->size / line_len;
58 unsigned src_offset = 0, src_pitch = 0, tiled = 1;
59 unsigned int exec = (1 << 20) | NVC0_M2MF_EXEC_LINEAR_OUT;
60 #endif
62 if (!nv50_style_tiled_pixmap(pspix)) {
64 tiled = 0;
65 src_pitch = exaGetPixmapPitch(pspix);
66 src_offset = (y * src_pitch) + (x * cpp);
67 #if defined(__AROS__)
68 exec |= NVC0_M2MF_EXEC_LINEAR_IN;
69 #endif
70 } else {
71 BEGIN_RING(chan, m2mf, NVC0_M2MF_TILING_MODE_IN, 5);
72 OUT_RING (chan, bo->tile_mode);
73 #if !defined(__AROS__)
74 OUT_RING (chan, pspix->drawable.width * cpp);
75 OUT_RING (chan, pspix->drawable.height);
76 #else
77 OUT_RING (chan, pspix->width * cpp);
78 OUT_RING (chan, pspix->height);
79 #endif
80 OUT_RING (chan, 1);
81 OUT_RING (chan, 0);
84 while (h) {
85 const char *src;
86 int line_count, i;
88 /* GART size >= 128 KiB assumed */
89 line_count = h;
90 if (line_count > line_limit)
91 line_count = line_limit;
93 MARK_RING(chan, 16, 4);
95 BEGIN_RING(chan, m2mf, NVC0_M2MF_OFFSET_OUT_HIGH, 2);
96 OUT_RELOCh(chan, pNv->GART, 0, NOUVEAU_BO(GART, GART, WR));
97 OUT_RELOCl(chan, pNv->GART, 0, NOUVEAU_BO(GART, GART, WR));
99 BEGIN_RING(chan, m2mf, NVC0_M2MF_OFFSET_IN_HIGH, 6);
100 OUT_RELOCh(chan, bo, src_offset, NOUVEAU_BO(VRAM, GART, RD));
101 OUT_RELOCl(chan, bo, src_offset, NOUVEAU_BO(VRAM, GART, RD));
102 OUT_RING (chan, src_pitch);
103 OUT_RING (chan, line_len);
104 OUT_RING (chan, line_len);
105 OUT_RING (chan, line_count);
107 if (tiled) {
108 BEGIN_RING(chan, m2mf,
109 NVC0_M2MF_TILING_POSITION_IN_X, 2);
110 OUT_RING (chan, x * cpp);
111 OUT_RING (chan, y);
114 BEGIN_RING(chan, m2mf, NVC0_M2MF_EXEC, 1);
115 #if !defined(__AROS__)
116 OUT_RING (chan, 0x100000 | (tiled << 8));
117 #else
118 OUT_RING (chan, exec | (tiled << 8));
119 #endif
121 if (nouveau_bo_map(pNv->GART, NOUVEAU_BO_RD)) {
122 MARK_UNDO(chan);
123 return FALSE;
125 src = pNv->GART->map;
127 #if !defined(__AROS__)
128 if (dst_pitch == line_len) {
129 memcpy(dst, src, dst_pitch * line_count);
130 dst += dst_pitch * line_count;
131 } else {
132 for (i = 0; i < line_count; ++i) {
133 memcpy(dst, src, line_len);
134 src += line_len;
135 dst += dst_pitch;
138 #else
139 (void)i;
140 HiddNouveauReadIntoRAM(
141 (char *)src, line_len,
142 dst, dst_pitch, dstPixFmt,
143 w, line_count,
144 cl, o);
145 dst += dst_pitch * line_count;
146 #endif
147 nouveau_bo_unmap(pNv->GART);
149 if (!tiled)
150 src_offset += line_count * src_pitch;
151 h -= line_count;
152 y += line_count;
155 return TRUE;
158 #if !defined(__AROS__)
159 Bool
160 NVC0AccelUploadM2MF(PixmapPtr pdpix, int x, int y, int w, int h,
161 const char *src, int src_pitch)
163 ScrnInfoPtr pScrn = xf86Screens[pdpix->drawable.pScreen->myNum];
164 #else
165 Bool
166 NVC0AccelUploadM2MF(PixmapPtr pdpix, int x, int y, int w, int h,
167 const char *src, int src_pitch,
168 HIDDT_StdPixFmt srcPixFmt, OOP_Class *cl, OOP_Object *o)
170 ScrnInfoPtr pScrn = globalcarddataptr;
171 #endif
172 NVPtr pNv = NVPTR(pScrn);
173 struct nouveau_channel *chan = pNv->chan;
174 struct nouveau_bo *bo = nouveau_pixmap_bo(pdpix);
175 struct nouveau_grobj *m2mf = pNv->NvMemFormat;
176 #if !defined(__AROS__)
177 int cpp = pdpix->drawable.bitsPerPixel / 8;
178 int line_len = w * cpp;
179 int line_limit = (128 << 10) / line_len;
180 unsigned dst_offset = 0, dst_pitch = 0, tiled = 1;
181 #else
182 int cpp = pdpix->depth > 16 ? 4 : 2;
183 int line_len = w * cpp;
184 int line_limit = pNv->GART->size / line_len;
185 unsigned dst_offset = 0, dst_pitch = 0, tiled = 1;
186 unsigned int exec = (1 << 20) | NVC0_M2MF_EXEC_LINEAR_IN;
187 #endif
189 if (!nv50_style_tiled_pixmap(pdpix)) {
190 tiled = 0;
191 dst_pitch = exaGetPixmapPitch(pdpix);
192 dst_offset = (y * dst_pitch) + (x * cpp);
193 #if defined(__AROS__)
194 exec |= NVC0_M2MF_EXEC_LINEAR_OUT;
195 #endif
196 } else {
197 BEGIN_RING(chan, m2mf, NVC0_M2MF_TILING_MODE_OUT, 5);
198 OUT_RING (chan, bo->tile_mode);
199 #if !defined(__AROS__)
200 OUT_RING (chan, pdpix->drawable.width * cpp);
201 OUT_RING (chan, pdpix->drawable.height);
202 #else
203 OUT_RING (chan, pdpix->width * cpp);
204 OUT_RING (chan, pdpix->height);
205 #endif
206 OUT_RING (chan, 1);
207 OUT_RING (chan, 0);
210 while (h) {
211 char *dst;
212 int i, line_count;
214 line_count = h;
215 if (line_count > line_limit)
216 line_count = line_limit;
218 if (nouveau_bo_map(pNv->GART, NOUVEAU_BO_WR))
219 return FALSE;
220 dst = pNv->GART->map;
222 #if !defined(__AROS__)
223 if (src_pitch == line_len) {
224 memcpy(dst, src, src_pitch * line_count);
225 src += src_pitch * line_count;
226 } else {
227 for (i = 0; i < line_count; i++) {
228 memcpy(dst, src, line_len);
229 src += src_pitch;
230 dst += line_len;
233 #else
234 (void)i;
235 HiddNouveauWriteFromRAM(
236 (APTR)src, src_pitch, srcPixFmt,
237 dst, line_len,
238 w, line_count,
239 cl, o);
240 src += src_pitch * line_count;
241 #endif
242 nouveau_bo_unmap(pNv->GART);
244 if (MARK_RING(chan, 16, 4))
245 return FALSE;
247 BEGIN_RING(chan, m2mf, NVC0_M2MF_OFFSET_IN_HIGH, 2);
248 OUT_RELOCh(chan, pNv->GART, 0, NOUVEAU_BO(GART, GART, RD));
249 OUT_RELOCl(chan, pNv->GART, 0, NOUVEAU_BO(GART, GART, RD));
251 BEGIN_RING(chan, m2mf, NVC0_M2MF_OFFSET_OUT_HIGH, 2);
252 OUT_RELOCh(chan, bo, dst_offset, NOUVEAU_BO(VRAM, GART, WR));
253 OUT_RELOCl(chan, bo, dst_offset, NOUVEAU_BO(VRAM, GART, WR));
255 if (tiled) {
256 BEGIN_RING(chan, m2mf,
257 NVC0_M2MF_TILING_POSITION_OUT_X, 2);
258 OUT_RING (chan, x * cpp);
259 OUT_RING (chan, y);
262 BEGIN_RING(chan, m2mf, NVC0_M2MF_PITCH_IN, 4);
263 OUT_RING (chan, line_len);
264 OUT_RING (chan, dst_pitch);
265 OUT_RING (chan, line_len);
266 OUT_RING (chan, line_count);
268 BEGIN_RING(chan, m2mf, NVC0_M2MF_EXEC, 1);
269 #if !defined(__AROS__)
270 OUT_RING (chan, 0x100000 | (tiled << 4));
271 #else
272 OUT_RING (chan, exec | (tiled << 4));
273 #endif
274 FIRE_RING (chan);
276 if (!tiled)
277 dst_offset += line_count * dst_pitch;
278 h -= line_count;
279 y += line_count;
282 return TRUE;
285 #if !defined(__AROS__)
286 struct nvc0_exa_state {
287 struct {
288 PictTransformPtr transform;
289 float width;
290 float height;
291 } unit[2];
293 Bool have_mask;
296 static struct nvc0_exa_state exa_state;
297 #endif
299 #if !defined(__AROS__)
300 #define NVC0EXA_LOCALS(p) \
301 ScrnInfoPtr pScrn = xf86Screens[(p)->drawable.pScreen->myNum]; \
302 NVPtr pNv = NVPTR(pScrn); \
303 struct nouveau_channel *chan = pNv->chan; (void)chan; \
304 struct nouveau_grobj *m2mf = pNv->NvMemFormat; (void)m2mf; \
305 struct nouveau_grobj *eng2d = pNv->Nv2D; (void)eng2d; \
306 struct nouveau_grobj *fermi = pNv->Nv3D; (void)fermi; \
307 struct nvc0_exa_state *state = &exa_state; (void)state
308 #else
309 #define NVC0EXA_LOCALS(p) \
310 ScrnInfoPtr pScrn = globalcarddataptr; \
311 NVPtr pNv = NVPTR(pScrn); \
312 struct nouveau_channel *chan = pNv->chan; (void)chan; \
313 struct nouveau_grobj *m2mf = pNv->NvMemFormat; (void)m2mf; \
314 struct nouveau_grobj *eng2d = pNv->Nv2D; (void)eng2d; \
315 struct nouveau_grobj *fermi = pNv->Nv3D; (void)fermi;
316 #endif
318 #if !defined(__AROS__)
319 #define BF(f) NV50_BLEND_FACTOR_##f
321 struct nvc0_blend_op {
322 unsigned src_alpha;
323 unsigned dst_alpha;
324 unsigned src_blend;
325 unsigned dst_blend;
328 static struct nvc0_blend_op
329 NVC0EXABlendOp[] = {
330 /* Clear */ { 0, 0, BF( ZERO), BF( ZERO) },
331 /* Src */ { 0, 0, BF( ONE), BF( ZERO) },
332 /* Dst */ { 0, 0, BF( ZERO), BF( ONE) },
333 /* Over */ { 1, 0, BF( ONE), BF(ONE_MINUS_SRC_ALPHA) },
334 /* OverReverse */ { 0, 1, BF(ONE_MINUS_DST_ALPHA), BF( ONE) },
335 /* In */ { 0, 1, BF( DST_ALPHA), BF( ZERO) },
336 /* InReverse */ { 1, 0, BF( ZERO), BF( SRC_ALPHA) },
337 /* Out */ { 0, 1, BF(ONE_MINUS_DST_ALPHA), BF( ZERO) },
338 /* OutReverse */ { 1, 0, BF( ZERO), BF(ONE_MINUS_SRC_ALPHA) },
339 /* Atop */ { 1, 1, BF( DST_ALPHA), BF(ONE_MINUS_SRC_ALPHA) },
340 /* AtopReverse */ { 1, 1, BF(ONE_MINUS_DST_ALPHA), BF( SRC_ALPHA) },
341 /* Xor */ { 1, 1, BF(ONE_MINUS_DST_ALPHA), BF(ONE_MINUS_SRC_ALPHA) },
342 /* Add */ { 0, 0, BF( ONE), BF( ONE) },
344 #endif
346 static Bool
347 NVC0EXA2DSurfaceFormat(PixmapPtr ppix, uint32_t *fmt)
349 NVC0EXA_LOCALS(ppix);
351 #if !defined(__AROS__)
352 switch (ppix->drawable.bitsPerPixel) {
353 #else
354 switch (ppix->depth) {
355 #endif
356 case 8 : *fmt = NV50_2D_SRC_FORMAT_R8_UNORM; break;
357 case 15: *fmt = NV50_2D_SRC_FORMAT_X1R5G5B5_UNORM; break;
358 case 16: *fmt = NV50_2D_SRC_FORMAT_R5G6B5_UNORM; break;
359 case 24: *fmt = NV50_2D_SRC_FORMAT_X8R8G8B8_UNORM; break;
360 case 30: *fmt = NV50_2D_SRC_FORMAT_A2B10G10R10_UNORM; break;
361 case 32: *fmt = NV50_2D_SRC_FORMAT_A8R8G8B8_UNORM; break;
362 default:
363 NOUVEAU_FALLBACK("Unknown surface format for bpp=%d\n",
364 ppix->drawable.bitsPerPixel);
365 return FALSE;
368 return TRUE;
371 static void NVC0EXASetClip(PixmapPtr ppix, int x, int y, int w, int h)
373 NVC0EXA_LOCALS(ppix);
375 BEGIN_RING(chan, eng2d, NV50_2D_CLIP_X, 4);
376 OUT_RING (chan, x);
377 OUT_RING (chan, y);
378 OUT_RING (chan, w);
379 OUT_RING (chan, h);
382 static Bool
383 NVC0EXAAcquireSurface2D(PixmapPtr ppix, int is_src)
385 NVC0EXA_LOCALS(ppix);
386 struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
387 int mthd = is_src ? NV50_2D_SRC_FORMAT : NV50_2D_DST_FORMAT;
388 uint32_t fmt, bo_flags;
390 if (!NVC0EXA2DSurfaceFormat(ppix, &fmt))
391 return FALSE;
393 bo_flags = NOUVEAU_BO_VRAM;
394 bo_flags |= is_src ? NOUVEAU_BO_RD : NOUVEAU_BO_WR;
396 if (!nv50_style_tiled_pixmap(ppix)) {
397 BEGIN_RING(chan, eng2d, mthd, 2);
398 OUT_RING (chan, fmt);
399 OUT_RING (chan, 1);
400 BEGIN_RING(chan, eng2d, mthd + 0x14, 1);
401 OUT_RING (chan, (uint32_t)exaGetPixmapPitch(ppix));
402 } else {
403 BEGIN_RING(chan, eng2d, mthd, 5);
404 OUT_RING (chan, fmt);
405 OUT_RING (chan, 0);
406 OUT_RING (chan, bo->tile_mode);
407 OUT_RING (chan, 1);
408 OUT_RING (chan, 0);
411 BEGIN_RING(chan, eng2d, mthd + 0x18, 4);
412 #if !defined(__AROS__)
413 OUT_RING (chan, ppix->drawable.width);
414 OUT_RING (chan, ppix->drawable.height);
415 #else
416 OUT_RING (chan, ppix->width);
417 OUT_RING (chan, ppix->height);
418 #endif
419 if (OUT_RELOCh(chan, bo, 0, bo_flags) ||
420 OUT_RELOCl(chan, bo, 0, bo_flags))
421 return FALSE;
423 if (is_src == 0)
424 #if !defined(__AROS__)
425 NVC0EXASetClip(ppix, 0, 0, ppix->drawable.width, ppix->drawable.height);
426 #else
427 NVC0EXASetClip(ppix, 0, 0, ppix->width, ppix->height);
428 #endif
430 return TRUE;
433 static void
434 NVC0EXASetPattern(PixmapPtr pdpix, int col0, int col1, int pat0, int pat1)
436 NVC0EXA_LOCALS(pdpix);
438 BEGIN_RING(chan, eng2d, NV50_2D_PATTERN_COLOR(0), 4);
439 OUT_RING (chan, col0);
440 OUT_RING (chan, col1);
441 OUT_RING (chan, pat0);
442 OUT_RING (chan, pat1);
445 #if !defined(__AROS__)
446 static void
447 NVC0EXASetROP(PixmapPtr pdpix, int alu, Pixel planemask)
449 NVC0EXA_LOCALS(pdpix);
450 int rop;
452 if (planemask != ~0)
453 rop = NVROP[alu].copy_planemask;
454 else
455 rop = NVROP[alu].copy;
457 BEGIN_RING(chan, eng2d, NV50_2D_OPERATION, 1);
458 if (alu == GXcopy && EXA_PM_IS_SOLID(&pdpix->drawable, planemask)) {
459 OUT_RING (chan, NV50_2D_OPERATION_SRCCOPY);
460 return;
461 } else {
462 OUT_RING (chan, NV50_2D_OPERATION_SRCCOPY_PREMULT);
465 BEGIN_RING(chan, eng2d, NV50_2D_PATTERN_FORMAT, 2);
466 switch (pdpix->drawable.bitsPerPixel) {
467 case 8: OUT_RING (chan, 3); break;
468 case 15: OUT_RING (chan, 1); break;
469 case 16: OUT_RING (chan, 0); break;
470 case 24:
471 case 32:
472 default:
473 OUT_RING (chan, 2);
474 break;
476 OUT_RING (chan, 1);
478 /* There are 16 ALUs.
479 * 0-15: copy
480 * 16-31: copy_planemask
483 if (!EXA_PM_IS_SOLID(&pdpix->drawable, planemask)) {
484 alu += 16;
485 NVC0EXASetPattern(pdpix, 0, planemask, ~0, ~0);
486 } else {
487 if (pNv->currentRop > 15)
488 NVC0EXASetPattern(pdpix, ~0, ~0, ~0, ~0);
491 if (pNv->currentRop != alu) {
492 BEGIN_RING(chan, eng2d, NV50_2D_ROP, 1);
493 OUT_RING (chan, rop);
494 pNv->currentRop = alu;
497 #else
498 static void
499 NVC0EXASetROP(PixmapPtr pdpix, int alu, Pixel planemask)
501 NVC0EXA_LOCALS(pdpix);
502 LONG rop;
504 rop = NVROP[alu].copy;
506 BEGIN_RING(chan, eng2d, NV50_2D_OPERATION, 1);
507 if (alu == 0x03 /* DrawMode_Copy */) {
508 OUT_RING (chan, NV50_2D_OPERATION_SRCCOPY);
509 return;
510 } else {
511 OUT_RING (chan, NV50_2D_OPERATION_SRCCOPY_PREMULT);
514 BEGIN_RING(chan, eng2d, NV50_2D_PATTERN_FORMAT, 2);
515 switch (pdpix->depth) {
516 case 8: OUT_RING (chan, 3); break;
517 case 15: OUT_RING (chan, 1); break;
518 case 16: OUT_RING (chan, 0); break;
519 case 24:
520 case 32:
521 default:
522 OUT_RING (chan, 2);
523 break;
525 OUT_RING (chan, 1);
527 BEGIN_RING(chan, eng2d, NV50_2D_ROP, 1);
528 OUT_RING (chan, rop);
530 #endif
532 #if !defined(__AROS__)
533 static void
534 NVC0EXAStateSolidResubmit(struct nouveau_channel *chan)
536 ScrnInfoPtr pScrn = chan->user_private;
537 NVPtr pNv = NVPTR(pScrn);
539 NVC0EXAPrepareSolid(pNv->pdpix, pNv->alu, pNv->planemask,
540 pNv->fg_colour);
542 #endif
544 Bool
545 NVC0EXAPrepareSolid(PixmapPtr pdpix, int alu, Pixel planemask, Pixel fg)
547 NVC0EXA_LOCALS(pdpix);
548 uint32_t fmt;
550 if (!NVC0EXA2DSurfaceFormat(pdpix, &fmt))
551 NOUVEAU_FALLBACK("rect format\n");
553 if (MARK_RING(chan, 64, 4))
554 NOUVEAU_FALLBACK("ring space\n");
556 if (!NVC0EXAAcquireSurface2D(pdpix, 0)) {
557 MARK_UNDO(chan);
558 NOUVEAU_FALLBACK("dest pixmap\n");
561 NVC0EXASetROP(pdpix, alu, planemask);
563 BEGIN_RING(chan, eng2d, NV50_2D_DRAW_SHAPE, 3);
564 OUT_RING (chan, NV50_2D_DRAW_SHAPE_RECTANGLES);
565 OUT_RING (chan, fmt);
566 OUT_RING (chan, fg);
568 #if !defined(__AROS__)
569 pNv->pdpix = pdpix;
570 pNv->alu = alu;
571 pNv->planemask = planemask;
572 pNv->fg_colour = fg;
573 chan->flush_notify = NVC0EXAStateSolidResubmit;
574 #else
575 chan->flush_notify = NULL;
576 #endif
577 return TRUE;
580 void
581 NVC0EXASolid(PixmapPtr pdpix, int x1, int y1, int x2, int y2)
583 NVC0EXA_LOCALS(pdpix);
585 WAIT_RING (chan, 5);
586 BEGIN_RING(chan, eng2d, NV50_2D_DRAW_POINT32_X(0), 4);
587 OUT_RING (chan, x1);
588 OUT_RING (chan, y1);
589 OUT_RING (chan, x2);
590 OUT_RING (chan, y2);
592 #if !defined(__AROS__)
593 if ((x2 - x1) * (y2 - y1) >= 512)
594 #endif
595 FIRE_RING (chan);
598 #if !defined(__AROS__)
599 void
600 NVC0EXADoneSolid(PixmapPtr pdpix)
602 NVC0EXA_LOCALS(pdpix);
604 chan->flush_notify = NULL;
607 static void
608 NVC0EXAStateCopyResubmit(struct nouveau_channel *chan)
610 ScrnInfoPtr pScrn = chan->user_private;
611 NVPtr pNv = NVPTR(pScrn);
613 NVC0EXAPrepareCopy(pNv->pspix, pNv->pdpix, 0, 0, pNv->alu,
614 pNv->planemask);
616 #endif
618 Bool
619 NVC0EXAPrepareCopy(PixmapPtr pspix, PixmapPtr pdpix, int dx, int dy,
620 int alu, Pixel planemask)
622 NVC0EXA_LOCALS(pdpix);
624 if (MARK_RING(chan, 64, 4))
625 NOUVEAU_FALLBACK("ring space\n");
627 if (!NVC0EXAAcquireSurface2D(pspix, 1)) {
628 MARK_UNDO(chan);
629 NOUVEAU_FALLBACK("src pixmap\n");
632 if (!NVC0EXAAcquireSurface2D(pdpix, 0)) {
633 MARK_UNDO(chan);
634 NOUVEAU_FALLBACK("dest pixmap\n");
637 NVC0EXASetROP(pdpix, alu, planemask);
639 #if !defined(__AROS__)
640 pNv->pspix = pspix;
641 pNv->pdpix = pdpix;
642 pNv->alu = alu;
643 pNv->planemask = planemask;
644 chan->flush_notify = NVC0EXAStateCopyResubmit;
645 #else
646 chan->flush_notify = NULL;
647 #endif
648 return TRUE;
651 void
652 NVC0EXACopy(PixmapPtr pdpix, int srcX , int srcY,
653 int dstX , int dstY,
654 int width, int height)
656 NVC0EXA_LOCALS(pdpix);
658 WAIT_RING (chan, 17);
659 BEGIN_RING(chan, eng2d, NV50_2D_SERIALIZE, 1);
660 OUT_RING (chan, 0);
661 BEGIN_RING(chan, eng2d, 0x088c, 1);
662 OUT_RING (chan, 0);
663 BEGIN_RING(chan, eng2d, NV50_2D_BLIT_DST_X, 12);
664 OUT_RING (chan, dstX);
665 OUT_RING (chan, dstY);
666 OUT_RING (chan, width);
667 OUT_RING (chan, height);
668 OUT_RING (chan, 0); /* DU,V_DX,Y_FRACT,INT */
669 OUT_RING (chan, 1);
670 OUT_RING (chan, 0);
671 OUT_RING (chan, 1);
672 OUT_RING (chan, 0); /* BLIT_SRC_X,Y_FRACT,INT */
673 OUT_RING (chan, srcX);
674 OUT_RING (chan, 0);
675 OUT_RING (chan, srcY);
677 #if !defined(__AROS__)
678 if (width * height >= 512)
679 #endif
680 FIRE_RING (chan);
683 #if !defined(__AROS__)
684 void
685 NVC0EXADoneCopy(PixmapPtr pdpix)
687 NVC0EXA_LOCALS(pdpix);
689 chan->flush_notify = NULL;
692 static void
693 NVC0EXAStateSIFCResubmit(struct nouveau_channel *chan)
695 ScrnInfoPtr pScrn = chan->user_private;
696 NVPtr pNv = NVPTR(pScrn);
698 if (MARK_RING(pNv->chan, 32, 2))
699 return;
701 if (!NVC0EXAAcquireSurface2D(pNv->pdpix, 0))
702 MARK_UNDO(pNv->chan);
705 Bool
706 NVC0EXAUploadSIFC(const char *src, int src_pitch,
707 PixmapPtr pdpix, int x, int y, int w, int h, int cpp)
709 NVC0EXA_LOCALS(pdpix);
710 ScreenPtr pScreen = pdpix->drawable.pScreen;
711 int line_dwords = (w * cpp + 3) / 4;
712 uint32_t sifc_fmt;
714 if (!NVC0EXA2DSurfaceFormat(pdpix, &sifc_fmt))
715 NOUVEAU_FALLBACK("hostdata format\n");
717 if (MARK_RING(chan, 64, 2))
718 return FALSE;
720 if (!NVC0EXAAcquireSurface2D(pdpix, 0)) {
721 MARK_UNDO(chan);
722 NOUVEAU_FALLBACK("dest pixmap\n");
725 /* If the pitch isn't aligned to a dword you can
726 * get corruption at the end of a line.
728 NVC0EXASetClip(pdpix, x, y, w, h);
730 BEGIN_RING(chan, eng2d, NV50_2D_OPERATION, 1);
731 OUT_RING (chan, NV50_2D_OPERATION_SRCCOPY);
732 BEGIN_RING(chan, eng2d, NV50_2D_SIFC_BITMAP_ENABLE, 2);
733 OUT_RING (chan, 0);
734 OUT_RING (chan, sifc_fmt);
735 BEGIN_RING(chan, eng2d, NV50_2D_SIFC_WIDTH, 10);
736 OUT_RING (chan, (line_dwords * 4) / cpp);
737 OUT_RING (chan, h);
738 OUT_RING (chan, 0); /* SIFC_DX,Y_DU,V_FRACT,INT */
739 OUT_RING (chan, 1);
740 OUT_RING (chan, 0);
741 OUT_RING (chan, 1);
742 OUT_RING (chan, 0); /* SIFC_DST_X,Y_FRACT,INT */
743 OUT_RING (chan, x);
744 OUT_RING (chan, 0);
745 OUT_RING (chan, y);
747 pNv->pdpix = pdpix;
748 chan->flush_notify = NVC0EXAStateSIFCResubmit;
750 while (h--) {
751 const char *ptr = src;
752 int count = line_dwords;
754 while (count) {
755 int size = count > 1792 ? 1792 : count;
757 WAIT_RING (chan, size + 1);
758 BEGIN_RING_NI(chan, eng2d, NV50_2D_SIFC_DATA, size);
759 OUT_RINGp (chan, ptr, size);
761 ptr += size * 4;
762 count -= size;
765 src += src_pitch;
768 chan->flush_notify = NULL;
770 if (pdpix == pScreen->GetScreenPixmap(pScreen))
771 FIRE_RING(chan);
772 return TRUE;
775 static Bool
776 NVC0EXACheckRenderTarget(PicturePtr ppict)
778 if (ppict->pDrawable->width > 8192 ||
779 ppict->pDrawable->height > 8192)
780 NOUVEAU_FALLBACK("render target dimensions exceeded %dx%d\n",
781 ppict->pDrawable->width,
782 ppict->pDrawable->height);
784 switch (ppict->format) {
785 case PICT_a8r8g8b8:
786 case PICT_x8r8g8b8:
787 case PICT_r5g6b5:
788 case PICT_a8:
789 case PICT_x1r5g5b5:
790 case PICT_a1r5g5b5:
791 case PICT_x8b8g8r8:
792 case PICT_a2b10g10r10:
793 case PICT_x2b10g10r10:
794 case PICT_a2r10g10b10:
795 case PICT_x2r10g10b10:
796 break;
797 default:
798 NOUVEAU_FALLBACK("picture format 0x%08x\n", ppict->format);
801 return TRUE;
804 static Bool
805 NVC0EXARenderTarget(PixmapPtr ppix, PicturePtr ppict)
807 NVC0EXA_LOCALS(ppix);
808 struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
809 unsigned format;
811 /*XXX: Scanout buffer not tiled, someone needs to figure it out */
812 if (!nv50_style_tiled_pixmap(ppix))
813 NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
815 switch (ppict->format) {
816 case PICT_a8r8g8b8: format = NV50_SURFACE_FORMAT_A8R8G8B8_UNORM; break;
817 case PICT_x8r8g8b8: format = NV50_SURFACE_FORMAT_X8R8G8B8_UNORM; break;
818 case PICT_r5g6b5: format = NV50_SURFACE_FORMAT_R5G6B5_UNORM; break;
819 case PICT_a8: format = NV50_SURFACE_FORMAT_A8_UNORM; break;
820 case PICT_x1r5g5b5: format = NV50_SURFACE_FORMAT_X1R5G5B5_UNORM; break;
821 case PICT_a1r5g5b5: format = NV50_SURFACE_FORMAT_A1R5G5B5_UNORM; break;
822 case PICT_x8b8g8r8: format = NV50_SURFACE_FORMAT_X8B8G8R8_UNORM; break;
823 case PICT_a2b10g10r10:
824 case PICT_x2b10g10r10:
825 format = NV50_SURFACE_FORMAT_A2B10G10R10_UNORM;
826 break;
827 case PICT_a2r10g10b10:
828 case PICT_x2r10g10b10:
829 format = NV50_SURFACE_FORMAT_A2R10G10B10_UNORM;
830 break;
831 default:
832 NOUVEAU_FALLBACK("invalid picture format\n");
835 BEGIN_RING(chan, fermi, NVC0_3D_RT_ADDRESS_HIGH(0), 8);
836 if (OUT_RELOCh(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR) ||
837 OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR))
838 return FALSE;
839 OUT_RING (chan, ppix->drawable.width);
840 OUT_RING (chan, ppix->drawable.height);
841 OUT_RING (chan, format);
842 OUT_RING (chan, bo->tile_mode);
843 OUT_RING (chan, 0x00000001);
844 OUT_RING (chan, 0x00000000);
846 return TRUE;
849 static Bool
850 NVC0EXACheckTexture(PicturePtr ppict, PicturePtr pdpict, int op)
852 if (!ppict->pDrawable)
853 NOUVEAU_FALLBACK("Solid and gradient pictures unsupported.\n");
855 if (ppict->pDrawable->width > 8192 ||
856 ppict->pDrawable->height > 8192)
857 NOUVEAU_FALLBACK("texture dimensions exceeded %dx%d\n",
858 ppict->pDrawable->width,
859 ppict->pDrawable->height);
861 switch (ppict->format) {
862 case PICT_a8r8g8b8:
863 case PICT_a8b8g8r8:
864 case PICT_x8r8g8b8:
865 case PICT_x8b8g8r8:
866 case PICT_r5g6b5:
867 case PICT_a8:
868 case PICT_x1r5g5b5:
869 case PICT_x1b5g5r5:
870 case PICT_a1r5g5b5:
871 case PICT_a1b5g5r5:
872 case PICT_b5g6r5:
873 case PICT_b8g8r8a8:
874 case PICT_b8g8r8x8:
875 case PICT_a2b10g10r10:
876 case PICT_x2b10g10r10:
877 case PICT_x2r10g10b10:
878 case PICT_a2r10g10b10:
879 case PICT_x4r4g4b4:
880 case PICT_x4b4g4r4:
881 case PICT_a4r4g4b4:
882 case PICT_a4b4g4r4:
883 break;
884 default:
885 NOUVEAU_FALLBACK("picture format 0x%08x\n", ppict->format);
888 switch (ppict->filter) {
889 case PictFilterNearest:
890 case PictFilterBilinear:
891 break;
892 default:
893 NOUVEAU_FALLBACK("picture filter %d\n", ppict->filter);
896 /* OpenGL and Render disagree on what should be sampled outside an XRGB
897 * texture (with no repeating). Opengl has a hardcoded alpha value of
898 * 1.0, while render expects 0.0. We assume that clipping is done for
899 * untranformed sources.
901 if (NVC0EXABlendOp[op].src_alpha && !ppict->repeat &&
902 ppict->transform && (PICT_FORMAT_A(ppict->format) == 0)
903 && (PICT_FORMAT_A(pdpict->format) != 0))
904 NOUVEAU_FALLBACK("REPEAT_NONE unsupported for XRGB source\n");
906 return TRUE;
909 #define _(X1, X2, X3, X4, FMT) \
910 (NV50TIC_0_0_TYPER_UNORM | NV50TIC_0_0_TYPEG_UNORM | \
911 NV50TIC_0_0_TYPEB_UNORM | NV50TIC_0_0_TYPEA_UNORM | \
912 NV50TIC_0_0_MAP##X1 | NV50TIC_0_0_MAP##X2 | \
913 NV50TIC_0_0_MAP##X3 | NV50TIC_0_0_MAP##X4 | \
914 NV50TIC_0_0_FMT_##FMT)
916 static Bool
917 NVC0EXATexture(PixmapPtr ppix, PicturePtr ppict, unsigned unit)
919 NVC0EXA_LOCALS(ppix);
920 struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
921 const unsigned tcb_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM;
922 uint32_t mode;
924 /* XXX: maybe add support for linear textures at some point */
925 if (!nv50_style_tiled_pixmap(ppix))
926 NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
928 BEGIN_RING(chan, fermi, NVC0_3D_TIC_ADDRESS_HIGH, 3);
929 if (OUT_RELOCh(chan, pNv->tesla_scratch, TIC_OFFSET, tcb_flags) ||
930 OUT_RELOCl(chan, pNv->tesla_scratch, TIC_OFFSET, tcb_flags))
931 return FALSE;
932 OUT_RING (chan, 15);
934 BEGIN_RING(chan, m2mf, NVC0_M2MF_OFFSET_OUT_HIGH, 2);
935 if (OUT_RELOCh(chan, pNv->tesla_scratch,
936 TIC_OFFSET + unit * 32, tcb_flags) ||
937 OUT_RELOCl(chan, pNv->tesla_scratch,
938 TIC_OFFSET + unit * 32, tcb_flags))
939 return FALSE;
940 BEGIN_RING(chan, m2mf, NVC0_M2MF_LINE_LENGTH_IN, 2);
941 OUT_RING (chan, 8 * 4);
942 OUT_RING (chan, 1);
943 BEGIN_RING(chan, m2mf, NVC0_M2MF_EXEC, 1);
944 OUT_RING (chan, 0x100111);
945 BEGIN_RING_NI(chan, m2mf, NVC0_M2MF_DATA, 8);
947 switch (ppict->format) {
948 case PICT_a8r8g8b8:
949 OUT_RING(chan, _(B_C0, G_C1, R_C2, A_C3, 8_8_8_8));
950 break;
951 case PICT_a8b8g8r8:
952 OUT_RING(chan, _(R_C0, G_C1, B_C2, A_C3, 8_8_8_8));
953 break;
954 case PICT_x8r8g8b8:
955 OUT_RING(chan, _(B_C0, G_C1, R_C2, A_ONE, 8_8_8_8));
956 break;
957 case PICT_x8b8g8r8:
958 OUT_RING(chan, _(R_C0, G_C1, B_C2, A_ONE, 8_8_8_8));
959 break;
960 case PICT_r5g6b5:
961 OUT_RING(chan, _(B_C0, G_C1, R_C2, A_ONE, 5_6_5));
962 break;
963 case PICT_a8:
964 OUT_RING(chan, _(A_C0, B_ZERO, G_ZERO, R_ZERO, 8));
965 break;
966 case PICT_x1r5g5b5:
967 OUT_RING(chan, _(B_C0, G_C1, R_C2, A_ONE, 1_5_5_5));
968 break;
969 case PICT_x1b5g5r5:
970 OUT_RING(chan, _(R_C0, G_C1, B_C2, A_ONE, 1_5_5_5));
971 break;
972 case PICT_a1r5g5b5:
973 OUT_RING(chan, _(B_C0, G_C1, R_C2, A_C3, 1_5_5_5));
974 break;
975 case PICT_a1b5g5r5:
976 OUT_RING(chan, _(R_C0, G_C1, B_C2, A_C3, 1_5_5_5));
977 break;
978 case PICT_b5g6r5:
979 OUT_RING(chan, _(R_C0, G_C1, B_C2, A_ONE, 5_6_5));
980 break;
981 case PICT_b8g8r8x8:
982 OUT_RING(chan, _(A_ONE, R_C1, G_C2, B_C3, 8_8_8_8));
983 break;
984 case PICT_b8g8r8a8:
985 OUT_RING(chan, _(A_C0, R_C1, G_C2, B_C3, 8_8_8_8));
986 break;
987 case PICT_a2b10g10r10:
988 OUT_RING(chan, _(R_C0, G_C1, B_C2, A_C3, 2_10_10_10));
989 break;
990 case PICT_x2b10g10r10:
991 OUT_RING(chan, _(R_C0, G_C1, B_C2, A_ONE, 2_10_10_10));
992 break;
993 case PICT_x2r10g10b10:
994 OUT_RING(chan, _(B_C0, G_C1, R_C2, A_ONE, 2_10_10_10));
995 break;
996 case PICT_a2r10g10b10:
997 OUT_RING(chan, _(B_C0, G_C1, R_C2, A_C3, 2_10_10_10));
998 break;
999 case PICT_x4r4g4b4:
1000 OUT_RING(chan, _(B_C0, G_C1, R_C2, A_ONE, 4_4_4_4));
1001 break;
1002 case PICT_x4b4g4r4:
1003 OUT_RING(chan, _(R_C0, G_C1, B_C2, A_ONE, 4_4_4_4));
1004 break;
1005 case PICT_a4r4g4b4:
1006 OUT_RING(chan, _(B_C0, G_C1, R_C2, A_C3, 4_4_4_4));
1007 break;
1008 case PICT_a4b4g4r4:
1009 OUT_RING(chan, _(R_C0, G_C1, B_C2, A_C3, 4_4_4_4));
1010 break;
1011 default:
1012 NOUVEAU_FALLBACK("invalid picture format, this SHOULD NOT HAPPEN. Expect trouble.\n");
1014 #undef _
1016 mode = 0xd0005000 | (bo->tile_mode << (22 - 4));
1017 if (OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD) ||
1018 OUT_RELOCd(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
1019 NOUVEAU_BO_HIGH | NOUVEAU_BO_OR, mode, mode))
1020 return FALSE;
1021 OUT_RING (chan, 0x00300000);
1022 OUT_RING (chan, (1 << 31) | ppix->drawable.width);
1023 OUT_RING (chan, (1 << 16) | ppix->drawable.height);
1024 OUT_RING (chan, 0x03000000);
1025 OUT_RING (chan, 0x00000000);
1027 BEGIN_RING(chan, fermi, NVC0_3D_TSC_ADDRESS_HIGH, 3);
1028 if (OUT_RELOCh(chan, pNv->tesla_scratch, TSC_OFFSET, tcb_flags) ||
1029 OUT_RELOCl(chan, pNv->tesla_scratch, TSC_OFFSET, tcb_flags))
1030 return FALSE;
1031 OUT_RING (chan, 0);
1033 BEGIN_RING(chan, m2mf, NVC0_M2MF_OFFSET_OUT_HIGH, 2);
1034 if (OUT_RELOCh(chan, pNv->tesla_scratch,
1035 TSC_OFFSET + unit * 32, tcb_flags) ||
1036 OUT_RELOCl(chan, pNv->tesla_scratch,
1037 TSC_OFFSET + unit * 32, tcb_flags))
1038 return FALSE;
1039 BEGIN_RING(chan, m2mf, NVC0_M2MF_LINE_LENGTH_IN, 2);
1040 OUT_RING (chan, 8 * 4);
1041 OUT_RING (chan, 1);
1042 BEGIN_RING(chan, m2mf, NVC0_M2MF_EXEC, 1);
1043 OUT_RING (chan, 0x100111);
1044 BEGIN_RING_NI(chan, m2mf, NVC0_M2MF_DATA, 8);
1046 if (ppict->repeat) {
1047 switch (ppict->repeatType) {
1048 case RepeatPad:
1049 OUT_RING (chan, 0x00024000 |
1050 NV50TSC_1_0_WRAPS_CLAMP |
1051 NV50TSC_1_0_WRAPT_CLAMP |
1052 NV50TSC_1_0_WRAPR_CLAMP);
1053 break;
1054 case RepeatReflect:
1055 OUT_RING (chan, 0x00024000 |
1056 NV50TSC_1_0_WRAPS_MIRROR_REPEAT |
1057 NV50TSC_1_0_WRAPT_MIRROR_REPEAT |
1058 NV50TSC_1_0_WRAPR_MIRROR_REPEAT);
1059 break;
1060 case RepeatNormal:
1061 default:
1062 OUT_RING (chan, 0x00024000 |
1063 NV50TSC_1_0_WRAPS_REPEAT |
1064 NV50TSC_1_0_WRAPT_REPEAT |
1065 NV50TSC_1_0_WRAPR_REPEAT);
1066 break;
1068 } else {
1069 OUT_RING (chan, 0x00024000 |
1070 NV50TSC_1_0_WRAPS_CLAMP_TO_BORDER |
1071 NV50TSC_1_0_WRAPT_CLAMP_TO_BORDER |
1072 NV50TSC_1_0_WRAPR_CLAMP_TO_BORDER);
1074 if (ppict->filter == PictFilterBilinear) {
1075 OUT_RING (chan,
1076 NV50TSC_1_1_MAGF_LINEAR |
1077 NV50TSC_1_1_MINF_LINEAR | NV50TSC_1_1_MIPF_NONE);
1078 } else {
1079 OUT_RING (chan,
1080 NV50TSC_1_1_MAGF_NEAREST |
1081 NV50TSC_1_1_MINF_NEAREST | NV50TSC_1_1_MIPF_NONE);
1083 OUT_RING (chan, 0x00000000);
1084 OUT_RING (chan, 0x00000000);
1085 OUT_RINGf (chan, 0.0f);
1086 OUT_RINGf (chan, 0.0f);
1087 OUT_RINGf (chan, 0.0f);
1088 OUT_RINGf (chan, 0.0f);
1090 state->unit[unit].width = ppix->drawable.width;
1091 state->unit[unit].height = ppix->drawable.height;
1092 state->unit[unit].transform = ppict->transform;
1093 return TRUE;
1096 static Bool
1097 NVC0EXACheckBlend(int op)
1099 if (op > PictOpAdd)
1100 NOUVEAU_FALLBACK("unsupported blend op %d\n", op);
1101 return TRUE;
1104 static void
1105 NVC0EXABlend(PixmapPtr ppix, PicturePtr ppict, int op, int component_alpha)
1107 NVC0EXA_LOCALS(ppix);
1108 struct nvc0_blend_op *b = &NVC0EXABlendOp[op];
1109 unsigned sblend = b->src_blend;
1110 unsigned dblend = b->dst_blend;
1112 if (b->dst_alpha) {
1113 if (!PICT_FORMAT_A(ppict->format)) {
1114 if (sblend == BF(DST_ALPHA))
1115 sblend = BF(ONE);
1116 else
1117 if (sblend == BF(ONE_MINUS_DST_ALPHA))
1118 sblend = BF(ZERO);
1122 if (b->src_alpha && component_alpha) {
1123 if (dblend == BF(SRC_ALPHA))
1124 dblend = BF(SRC_COLOR);
1125 else
1126 if (dblend == BF(ONE_MINUS_SRC_ALPHA))
1127 dblend = BF(ONE_MINUS_SRC_COLOR);
1130 if (sblend == BF(ONE) && dblend == BF(ZERO)) {
1131 BEGIN_RING(chan, fermi, NVC0_3D_BLEND_ENABLE(0), 1);
1132 OUT_RING (chan, 0);
1133 } else {
1134 BEGIN_RING(chan, fermi, NVC0_3D_BLEND_ENABLE(0), 1);
1135 OUT_RING (chan, 1);
1136 BEGIN_RING(chan, fermi, NVC0_3D_BLEND_EQUATION_RGB, 5);
1137 OUT_RING (chan, NVC0_3D_BLEND_EQUATION_RGB_FUNC_ADD);
1138 OUT_RING (chan, sblend);
1139 OUT_RING (chan, dblend);
1140 OUT_RING (chan, NVC0_3D_BLEND_EQUATION_ALPHA_FUNC_ADD);
1141 OUT_RING (chan, sblend);
1142 BEGIN_RING(chan, fermi, NVC0_3D_BLEND_FUNC_DST_ALPHA, 1);
1143 OUT_RING (chan, dblend);
1147 Bool
1148 NVC0EXACheckComposite(int op,
1149 PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict)
1151 if (!NVC0EXACheckBlend(op))
1152 NOUVEAU_FALLBACK("blend not supported\n");
1154 if (!NVC0EXACheckRenderTarget(pdpict))
1155 NOUVEAU_FALLBACK("render target invalid\n");
1157 if (!NVC0EXACheckTexture(pspict, pdpict, op))
1158 NOUVEAU_FALLBACK("src picture invalid\n");
1160 if (pmpict) {
1161 if (pmpict->componentAlpha &&
1162 PICT_FORMAT_RGB(pmpict->format) &&
1163 NVC0EXABlendOp[op].src_alpha &&
1164 NVC0EXABlendOp[op].src_blend != BF(ZERO))
1165 NOUVEAU_FALLBACK("component-alpha not supported\n");
1167 if (!NVC0EXACheckTexture(pmpict, pdpict, op))
1168 NOUVEAU_FALLBACK("mask picture invalid\n");
1171 return TRUE;
1174 static void
1175 NVC0EXAStateCompositeResubmit(struct nouveau_channel *chan)
1177 ScrnInfoPtr pScrn = chan->user_private;
1178 NVPtr pNv = NVPTR(pScrn);
1180 NVC0EXAPrepareComposite(pNv->alu, pNv->pspict, pNv->pmpict, pNv->pdpict,
1181 pNv->pspix, pNv->pmpix, pNv->pdpix);
1184 Bool
1185 NVC0EXAPrepareComposite(int op,
1186 PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict,
1187 PixmapPtr pspix, PixmapPtr pmpix, PixmapPtr pdpix)
1189 NVC0EXA_LOCALS(pspix);
1190 const unsigned shd_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD;
1192 if (MARK_RING (chan, 128, 4 + 2 + 2 * 10))
1193 NOUVEAU_FALLBACK("ring space\n");
1195 // fonts: !pmpict, op == 12 (Add, ONE/ONE)
1197 if (pmpict || op != 12)
1198 NOUVEAU_FALLBACK("comp-alpha");
1201 BEGIN_RING(chan, eng2d, NV50_2D_SERIALIZE, 1);
1202 OUT_RING (chan, 0);
1204 if (!NVC0EXARenderTarget(pdpix, pdpict)) {
1205 MARK_UNDO(chan);
1206 NOUVEAU_FALLBACK("render target invalid\n");
1209 NVC0EXABlend(pdpix, pdpict, op, pmpict && pmpict->componentAlpha &&
1210 PICT_FORMAT_RGB(pmpict->format));
1212 BEGIN_RING(chan, fermi, NVC0_3D_CODE_ADDRESS_HIGH, 2);
1213 if (OUT_RELOCh(chan, pNv->tesla_scratch, CODE_OFFSET, shd_flags) ||
1214 OUT_RELOCl(chan, pNv->tesla_scratch, CODE_OFFSET, shd_flags)) {
1215 MARK_UNDO(chan);
1216 return FALSE;
1219 if (!NVC0EXATexture(pspix, pspict, 0)) {
1220 MARK_UNDO(chan);
1221 NOUVEAU_FALLBACK("src picture invalid\n");
1223 BEGIN_RING(chan, fermi, NVC0_3D_BIND_TIC(4), 1);
1224 OUT_RING (chan, (0 << 9) | (0 << 1) | NVC0_3D_BIND_TIC_ACTIVE);
1226 if (pmpict) {
1227 if (!NVC0EXATexture(pmpix, pmpict, 1)) {
1228 MARK_UNDO(chan);
1229 NOUVEAU_FALLBACK("mask picture invalid\n");
1231 state->have_mask = TRUE;
1233 BEGIN_RING(chan, fermi, NVC0_3D_BIND_TIC(4), 1);
1234 OUT_RING (chan, (1 << 9) | (1 << 1) | NVC0_3D_BIND_TIC_ACTIVE);
1236 BEGIN_RING(chan, fermi, NVC0_3D_SP_START_ID(5), 1);
1237 if (pdpict->format == PICT_a8) {
1238 OUT_RING (chan, PFP_C_A8);
1239 } else {
1240 if (pmpict->componentAlpha &&
1241 PICT_FORMAT_RGB(pmpict->format)) {
1242 if (NVC0EXABlendOp[op].src_alpha)
1243 OUT_RING (chan, PFP_CCASA);
1244 else
1245 OUT_RING (chan, PFP_CCA);
1246 } else {
1247 OUT_RING (chan, PFP_C);
1250 } else {
1251 state->have_mask = FALSE;
1253 BEGIN_RING(chan, fermi, NVC0_3D_BIND_TIC(4), 1);
1254 OUT_RING (chan, (1 << 1) | 0);
1256 BEGIN_RING(chan, fermi, NVC0_3D_SP_START_ID(5), 1);
1257 if (pdpict->format == PICT_a8)
1258 OUT_RING (chan, PFP_S_A8);
1259 else
1260 OUT_RING (chan, PFP_S);
1263 BEGIN_RING(chan, fermi, NVC0_3D_TSC_FLUSH, 1);
1264 OUT_RING (chan, 0);
1265 BEGIN_RING(chan, fermi, NVC0_3D_TIC_FLUSH, 1);
1266 OUT_RING (chan, 0);
1267 BEGIN_RING(chan, fermi, NVC0_3D_TEX_CACHE_CTL, 1);
1268 OUT_RING (chan, 0);
1270 pNv->alu = op;
1271 pNv->pspict = pspict;
1272 pNv->pmpict = pmpict;
1273 pNv->pdpict = pdpict;
1274 pNv->pspix = pspix;
1275 pNv->pmpix = pmpix;
1276 pNv->pdpix = pdpix;
1277 chan->flush_notify = NVC0EXAStateCompositeResubmit;
1278 return TRUE;
1281 #define xFixedToFloat(v) \
1282 ((float)xFixedToInt((v)) + ((float)xFixedFrac(v) / 65536.0))
1284 static inline void
1285 NVC0EXATransform(PictTransformPtr t, int x, int y, float sx, float sy,
1286 float *x_ret, float *y_ret)
1288 if (t) {
1289 PictVector v;
1291 v.vector[0] = IntToxFixed(x);
1292 v.vector[1] = IntToxFixed(y);
1293 v.vector[2] = xFixed1;
1294 PictureTransformPoint(t, &v);
1295 *x_ret = xFixedToFloat(v.vector[0]) / sx;
1296 *y_ret = xFixedToFloat(v.vector[1]) / sy;
1297 } else {
1298 *x_ret = (float)x / sx;
1299 *y_ret = (float)y / sy;
1303 void
1304 NVC0EXAComposite(PixmapPtr pdpix,
1305 int sx, int sy, int mx, int my,
1306 int dx, int dy, int w, int h)
1308 NVC0EXA_LOCALS(pdpix);
1309 float sX0, sX1, sX2, sY0, sY1, sY2;
1311 WAIT_RING (chan, 64);
1312 BEGIN_RING(chan, fermi, NVC0_3D_SCISSOR_HORIZ(0), 2);
1313 OUT_RING (chan, ((dx + w) << 16) | dx);
1314 OUT_RING (chan, ((dy + h) << 16) | dy);
1315 BEGIN_RING(chan, fermi, NVC0_3D_VERTEX_BEGIN_GL, 1);
1316 OUT_RING (chan, NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_TRIANGLES);
1318 NVC0EXATransform(state->unit[0].transform, sx, sy + (h * 2),
1319 state->unit[0].width, state->unit[0].height,
1320 &sX0, &sY0);
1321 NVC0EXATransform(state->unit[0].transform, sx, sy,
1322 state->unit[0].width, state->unit[0].height,
1323 &sX1, &sY1);
1324 NVC0EXATransform(state->unit[0].transform, sx + (w * 2), sy,
1325 state->unit[0].width, state->unit[0].height,
1326 &sX2, &sY2);
1328 if (state->have_mask) {
1329 float mX0, mX1, mX2, mY0, mY1, mY2;
1331 NVC0EXATransform(state->unit[1].transform, mx, my + (h * 2),
1332 state->unit[1].width, state->unit[1].height,
1333 &mX0, &mY0);
1334 NVC0EXATransform(state->unit[1].transform, mx, my,
1335 state->unit[1].width, state->unit[1].height,
1336 &mX1, &mY1);
1337 NVC0EXATransform(state->unit[1].transform, mx + (w * 2), my,
1338 state->unit[1].width, state->unit[1].height,
1339 &mX2, &mY2);
1341 VTX2s(pNv, sX0, sY0, mX0, mY0, dx, dy + (h * 2));
1342 VTX2s(pNv, sX1, sY1, mX1, mY1, dx, dy);
1343 VTX2s(pNv, sX2, sY2, mX2, mY2, dx + (w * 2), dy);
1344 } else {
1345 VTX1s(pNv, sX0, sY0, dx, dy + (h * 2));
1346 VTX1s(pNv, sX1, sY1, dx, dy);
1347 VTX1s(pNv, sX2, sY2, dx + (w * 2), dy);
1350 BEGIN_RING(chan, fermi, NVC0_3D_VERTEX_END_GL, 1);
1351 OUT_RING (chan, 0);
1354 void
1355 NVC0EXADoneComposite(PixmapPtr pdpix)
1357 NVC0EXA_LOCALS(pdpix);
1359 chan->flush_notify = NULL;
1361 #endif
1363 /* AROS CODE */
1365 VOID HIDDNouveauNVC0SetPattern(struct CardData * carddata, LONG clr0, LONG clr1,
1366 LONG pat0, LONG pat1)
1368 NVC0EXASetPattern(NULL, clr0, clr1, pat0, pat1);
1371 /* NOTE: Assumes lock on bitmap is already made */
1372 /* NOTE: Assumes buffer is not mapped */
1373 BOOL HIDDNouveauNVC0FillSolidRect(struct CardData * carddata,
1374 struct HIDDNouveauBitMapData * bmdata, LONG minX, LONG minY, LONG maxX,
1375 LONG maxY, ULONG drawmode, ULONG color)
1377 if (NVC0EXAPrepareSolid(bmdata, drawmode, ~0, color))
1379 NVC0EXASolid(bmdata, minX, minY, maxX + 1, maxY + 1);
1380 return TRUE;
1383 return FALSE;
1386 /* NOTE: Assumes lock on both bitmaps is already made */
1387 /* NOTE: Assumes both buffers are not mapped */
1388 BOOL HIDDNouveauNVC0CopySameFormat(struct CardData * carddata,
1389 struct HIDDNouveauBitMapData * srcdata, struct HIDDNouveauBitMapData * destdata,
1390 LONG srcX, LONG srcY, LONG destX, LONG destY, LONG width, LONG height,
1391 ULONG drawmode)
1393 if (NVC0EXAPrepareCopy(srcdata, destdata, 0, 0, drawmode, ~0))
1395 NVC0EXACopy(destdata, srcX, srcY, destX , destY, width, height);
1396 return TRUE;
1399 return FALSE;