Hint added.
[AROS.git] / workbench / hidds / nouveau / xf86-video-nouveau / nv04_exa.c
blobea7068ad9bd5922da10e8d726659937c613e6fa2
1 /*
2 * Copyright 2003 NVIDIA, Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
23 #include "nv_include.h"
24 #include "nv_rop.h"
26 #include "nv04_pushbuf.h"
28 static void
29 NV04EXASetPattern(ScrnInfoPtr pScrn, CARD32 clr0, CARD32 clr1,
30 CARD32 pat0, CARD32 pat1)
32 NVPtr pNv = NVPTR(pScrn);
33 struct nouveau_channel *chan = pNv->chan;
34 struct nouveau_grobj *patt = pNv->NvImagePattern;
36 BEGIN_RING(chan, patt, NV04_IMAGE_PATTERN_MONOCHROME_COLOR0, 4);
37 OUT_RING (chan, clr0);
38 OUT_RING (chan, clr1);
39 OUT_RING (chan, pat0);
40 OUT_RING (chan, pat1);
43 #if !defined(__AROS__)
44 static void
45 NV04EXASetROP(ScrnInfoPtr pScrn, CARD32 alu, CARD32 planemask)
47 NVPtr pNv = NVPTR(pScrn);
48 struct nouveau_channel *chan = pNv->chan;
49 struct nouveau_grobj *rop = pNv->NvRop;
51 if (planemask != ~0) {
52 NV04EXASetPattern(pScrn, 0, planemask, ~0, ~0);
53 if (pNv->currentRop != (alu + 32)) {
54 BEGIN_RING(chan, rop, NV03_CONTEXT_ROP_ROP, 1);
55 OUT_RING (chan, NVROP[alu].copy_planemask);
56 pNv->currentRop = alu + 32;
58 } else
59 if (pNv->currentRop != alu) {
60 if(pNv->currentRop >= 16)
61 NV04EXASetPattern(pScrn, ~0, ~0, ~0, ~0);
62 BEGIN_RING(chan, rop, NV03_CONTEXT_ROP_ROP, 1);
63 OUT_RING (chan, NVROP[alu].copy);
64 pNv->currentRop = alu;
67 #else
68 static void
69 NV04EXASetROP(ScrnInfoPtr pScrn, CARD32 alu, CARD32 planemask)
71 NVPtr pNv = NVPTR(pScrn);
72 struct nouveau_channel *chan = pNv->chan;
73 struct nouveau_grobj *rop = pNv->NvRop;
75 BEGIN_RING(chan, rop, NV03_CONTEXT_ROP_ROP, 1);
76 OUT_RING (chan, NVROP[alu].copy);
78 #endif
80 #if !defined(__AROS__)
81 static void
82 NV04EXAStateSolidResubmit(struct nouveau_channel *chan)
84 ScrnInfoPtr pScrn = chan->user_private;
85 NVPtr pNv = NVPTR(pScrn);
87 NV04EXAPrepareSolid(pNv->pdpix, pNv->alu, pNv->planemask, pNv->fg_colour);
89 #endif
91 Bool
92 NV04EXAPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg)
94 #if !defined(__AROS__)
95 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
96 #else
97 ScrnInfoPtr pScrn = globalcarddataptr;
98 #endif
99 NVPtr pNv = NVPTR(pScrn);
100 struct nouveau_channel *chan = pNv->chan;
101 struct nouveau_grobj *surf2d = pNv->NvContextSurfaces;
102 struct nouveau_grobj *rect = pNv->NvRectangle;
103 struct nouveau_bo *bo = nouveau_pixmap_bo(pPixmap);
104 unsigned int fmt, pitch, fmt2 = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
106 if (MARK_RING(chan, 64, 2))
107 return FALSE;
109 #if !defined(__AROS__)
110 planemask |= ~0 << pPixmap->drawable.bitsPerPixel;
111 if (planemask != ~0 || alu != GXcopy) {
112 if (pPixmap->drawable.bitsPerPixel == 32)
113 return FALSE;
114 #else
115 if (alu != 0x03 /* DrawMode_Copy */) {
116 #endif
117 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
118 OUT_RING (chan, 1); /* ROP_AND */
119 NV04EXASetROP(pScrn, alu, planemask);
120 } else {
121 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
122 OUT_RING (chan, 3); /* SRCCOPY */
125 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pPixmap, (int*)&fmt))
126 return FALSE;
127 pitch = exaGetPixmapPitch(pPixmap);
129 #if !defined(__AROS__)
130 if (pPixmap->drawable.bitsPerPixel == 16) {
131 if (pPixmap->drawable.depth == 16) {
132 fmt2 = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
133 } else if (pPixmap->drawable.depth == 15) {
134 fmt2 = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_X16A1R5G5B5;
137 #else
138 if (pPixmap->depth == 16)
139 fmt2 = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
140 #endif
142 /* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the
143 * alpha channel gets forced to 0xFF for some reason. We're using
144 * SURFACE_FORMAT_Y32 as a workaround
146 if (fmt == NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8)
147 fmt = NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
149 BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
150 OUT_RING (chan, fmt);
151 OUT_RING (chan, (pitch << 16) | pitch);
152 if (OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR) ||
153 OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
154 MARK_UNDO(chan);
155 return FALSE;
158 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
159 OUT_RING (chan, fmt2);
160 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
161 OUT_RING (chan, fg);
163 #if !defined(__AROS__)
164 pNv->pdpix = pPixmap;
165 pNv->alu = alu;
166 pNv->planemask = planemask;
167 pNv->fg_colour = fg;
168 chan->flush_notify = NV04EXAStateSolidResubmit;
169 #else
170 chan->flush_notify = NULL;
171 #endif
172 return TRUE;
175 void
176 NV04EXASolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
178 #if !defined(__AROS__)
179 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
180 #else
181 ScrnInfoPtr pScrn = globalcarddataptr;
182 #endif
183 NVPtr pNv = NVPTR(pScrn);
184 struct nouveau_channel *chan = pNv->chan;
185 struct nouveau_grobj *rect = pNv->NvRectangle;
186 int width = x2-x1;
187 int height = y2-y1;
189 BEGIN_RING(chan, rect,
190 NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
191 OUT_RING (chan, (x1 << 16) | y1);
192 OUT_RING (chan, (width << 16) | height);
194 #if !defined(__AROS__)
195 if((width * height) >= 512)
196 #endif
197 FIRE_RING (chan);
200 #if !defined(__AROS__)
201 void
202 NV04EXADoneSolid (PixmapPtr pPixmap)
204 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
205 NVPtr pNv = NVPTR(pScrn);
207 pNv->chan->flush_notify = NULL;
210 static void
211 NV04EXAStateCopyResubmit(struct nouveau_channel *chan)
213 ScrnInfoPtr pScrn = chan->user_private;
214 NVPtr pNv = NVPTR(pScrn);
216 NV04EXAPrepareCopy(pNv->pspix, pNv->pdpix, 0, 0, pNv->alu,
217 pNv->planemask);
219 #endif
221 Bool
222 NV04EXAPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int dx, int dy,
223 int alu, Pixel planemask)
225 #if !defined(__AROS__)
226 ScrnInfoPtr pScrn = xf86Screens[pSrcPixmap->drawable.pScreen->myNum];
227 #else
228 ScrnInfoPtr pScrn = globalcarddataptr;
229 #endif
230 NVPtr pNv = NVPTR(pScrn);
231 struct nouveau_channel *chan = pNv->chan;
232 struct nouveau_grobj *surf2d = pNv->NvContextSurfaces;
233 struct nouveau_grobj *blit = pNv->NvImageBlit;
234 struct nouveau_bo *src_bo = nouveau_pixmap_bo(pSrcPixmap);
235 struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pDstPixmap);
236 int fmt;
238 #if !defined(__AROS__)
239 if (pSrcPixmap->drawable.bitsPerPixel !=
240 pDstPixmap->drawable.bitsPerPixel)
241 #else
242 if (pSrcPixmap->depth != pDstPixmap->depth)
243 #endif
244 return FALSE;
246 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDstPixmap, &fmt))
247 return FALSE;
249 if (MARK_RING(chan, 64, 2))
250 return FALSE;
252 #if !defined(__AROS__)
253 planemask |= ~0 << pDstPixmap->drawable.bitsPerPixel;
254 if (planemask != ~0 || alu != GXcopy) {
255 if (pDstPixmap->drawable.bitsPerPixel == 32) {
256 MARK_UNDO(chan);
257 return FALSE;
259 #else
260 if (alu != 0x03 /* DrawMode_Copy */) {
261 #endif
263 BEGIN_RING(chan, blit, NV01_IMAGE_BLIT_OPERATION, 1);
264 OUT_RING (chan, 1); /* ROP_AND */
266 NV04EXASetROP(pScrn, alu, planemask);
267 } else {
268 BEGIN_RING(chan, blit, NV01_IMAGE_BLIT_OPERATION, 1);
269 OUT_RING (chan, 3); /* SRCCOPY */
272 BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
273 OUT_RING (chan, fmt);
274 OUT_RING (chan, (exaGetPixmapPitch(pDstPixmap) << 16) |
275 (exaGetPixmapPitch(pSrcPixmap)));
276 if (OUT_RELOCl(chan, src_bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD) ||
277 OUT_RELOCl(chan, dst_bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
278 MARK_UNDO(chan);
279 return FALSE;
282 #if !defined(__AROS__)
283 pNv->pspix = pSrcPixmap;
284 pNv->pdpix = pDstPixmap;
285 pNv->alu = alu;
286 pNv->planemask = planemask;
287 chan->flush_notify = NV04EXAStateCopyResubmit;
288 #else
289 chan->flush_notify = NULL;
290 #endif
291 return TRUE;
294 void
295 NV04EXACopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY,
296 int width, int height)
298 #if !defined(__AROS__)
299 ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
300 #else
301 ScrnInfoPtr pScrn = globalcarddataptr;
302 #endif
303 NVPtr pNv = NVPTR(pScrn);
304 struct nouveau_channel *chan = pNv->chan;
305 struct nouveau_grobj *blit = pNv->NvImageBlit;
306 #if !defined(__AROS__)
307 int split_dstY = NOUVEAU_ALIGN(dstY + 1, 64);
308 int split_height = split_dstY - dstY;
310 if ((width * height) >= 200000 && pNv->pspix != pNv->pdpix &&
311 (dstY > srcY || dstX > srcX) && split_height < height) {
313 * KLUDGE - Split the destination rectangle in an
314 * upper misaligned half and a lower tile-aligned
315 * half, then get IMAGE_BLIT to blit the lower piece
316 * downwards (required for sync-to-vblank if the area
317 * to be blitted is large enough). The blob does a
318 * different (not nicer) trick to achieve the same
319 * effect.
321 struct nouveau_grobj *surf2d = pNv->NvContextSurfaces;
322 struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pNv->pdpix);
323 unsigned dst_pitch = exaGetPixmapPitch(pNv->pdpix);
325 if (MARK_RING(chan, 10, 1))
326 return;
328 BEGIN_RING(chan, blit, NV01_IMAGE_BLIT_POINT_IN, 3);
329 OUT_RING (chan, (srcY << 16) | srcX);
330 OUT_RING (chan, (dstY << 16) | dstX);
331 OUT_RING (chan, (split_height << 16) | width);
333 BEGIN_RING(chan, surf2d,
334 NV04_CONTEXT_SURFACES_2D_OFFSET_DESTIN, 1);
335 OUT_RELOCl(chan, dst_bo, split_dstY * dst_pitch,
336 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
338 srcY += split_height;
339 height -= split_height;
340 dstY = 0;
342 #endif
344 BEGIN_RING(chan, blit, NV01_IMAGE_BLIT_POINT_IN, 3);
345 OUT_RING (chan, (srcY << 16) | srcX);
346 OUT_RING (chan, (dstY << 16) | dstX);
347 OUT_RING (chan, (height << 16) | width);
349 #if !defined(__AROS__)
350 if((width * height) >= 512)
351 #endif
352 FIRE_RING (chan);
355 #if !defined(__AROS__)
356 void
357 NV04EXADoneCopy(PixmapPtr pDstPixmap)
359 ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
360 NVPtr pNv = NVPTR(pScrn);
362 pNv->chan->flush_notify = NULL;
365 static Bool
366 NV04EXAStateIFCSubmit(struct nouveau_channel *chan)
368 ScrnInfoPtr pScrn = chan->user_private;
369 NVPtr pNv = NVPTR(pScrn);
370 struct nouveau_grobj *surf2d = pNv->NvContextSurfaces;
371 struct nouveau_grobj *ifc = pNv->NvImageFromCpu;
372 struct nouveau_bo *bo = nouveau_pixmap_bo(pNv->pdpix);
373 int surf_fmt;
375 NVAccelGetCtxSurf2DFormatFromPixmap(pNv->pdpix, &surf_fmt);
377 if (MARK_RING(chan, 64, 2))
378 return FALSE;
380 BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
381 OUT_RING (chan, surf_fmt);
382 OUT_RING (chan, (exaGetPixmapPitch(pNv->pdpix) << 16) |
383 exaGetPixmapPitch(pNv->pdpix));
384 if (OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR) ||
385 OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
386 MARK_UNDO(chan);
387 return FALSE;
389 BEGIN_RING(chan, ifc, NV01_IMAGE_FROM_CPU_POINT, 3);
390 OUT_RING (chan, (pNv->point_y << 16) | pNv->point_x);
391 OUT_RING (chan, (pNv->height_out << 16) | pNv->width_out);
392 OUT_RING (chan, (pNv->height_in << 16) | pNv->width_in);
394 return TRUE;
397 static void
398 NV04EXAStateIFCResubmit(struct nouveau_channel *chan)
400 NV04EXAStateIFCSubmit(chan);
403 Bool
404 NV04EXAUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch,
405 PixmapPtr pDst, int x, int y, int w, int h, int cpp)
407 NVPtr pNv = NVPTR(pScrn);
408 ScreenPtr pScreen = pDst->drawable.pScreen;
409 struct nouveau_channel *chan = pNv->chan;
410 struct nouveau_grobj *clip = pNv->NvClipRectangle;
411 struct nouveau_grobj *ifc = pNv->NvImageFromCpu;
412 int line_len = w * cpp;
413 int iw, id, surf_fmt, ifc_fmt;
414 int padbytes;
416 if (pNv->Architecture >= NV_ARCH_50)
417 return FALSE;
419 if (h > 1024)
420 return FALSE;
422 if (line_len<4)
423 return FALSE;
425 switch (cpp) {
426 case 2: ifc_fmt = 1; break;
427 case 4: ifc_fmt = 4; break;
428 default:
429 return FALSE;
432 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDst, &surf_fmt))
433 return FALSE;
435 /* Pad out input width to cover both COLORA() and COLORB() */
436 iw = (line_len + 7) & ~7;
437 padbytes = iw - line_len;
438 id = iw / 4; /* line push size */
439 iw /= cpp;
441 /* Don't support lines longer than max push size yet.. */
442 if (id > 1792)
443 return FALSE;
445 BEGIN_RING(chan, clip, NV01_CONTEXT_CLIP_RECTANGLE_POINT, 2);
446 OUT_RING (chan, (y << 16) | x);
447 OUT_RING (chan, (h << 16) | w);
448 BEGIN_RING(chan, ifc, NV01_IMAGE_FROM_CPU_OPERATION, 2);
449 OUT_RING (chan, NV01_IMAGE_FROM_CPU_OPERATION_SRCCOPY);
450 OUT_RING (chan, ifc_fmt);
452 pNv->point_x = x;
453 pNv->point_y = y;
454 pNv->height_in = pNv->height_out = h;
455 pNv->width_in = iw;
456 pNv->width_out = w;
457 pNv->pdpix = pDst;
458 chan->flush_notify = NV04EXAStateIFCResubmit;
459 if (!NV04EXAStateIFCSubmit(chan))
460 return FALSE;
462 if (padbytes)
463 h--;
464 while (h--) {
465 /* send a line */
466 BEGIN_RING(chan, ifc, NV01_IMAGE_FROM_CPU_COLOR(0), id);
467 OUT_RINGp (chan, src, id);
469 src += src_pitch;
470 pNv->point_y++;
472 if (padbytes) {
473 char padding[8];
474 int aux = (padbytes + 7) >> 2;
475 BEGIN_RING(chan, ifc, NV01_IMAGE_FROM_CPU_COLOR(0), id);
476 OUT_RINGp (chan, src, id - aux);
477 memcpy(padding, src + (id - aux) * 4, padbytes);
478 OUT_RINGp (chan, padding, aux);
481 chan->flush_notify = NULL;
483 if (pDst == pScreen->GetScreenPixmap(pScreen))
484 FIRE_RING(chan);
485 return TRUE;
487 #endif
489 /* AROS CODE */
491 VOID HIDDNouveauNV04SetPattern(struct CardData * carddata, LONG clr0, LONG clr1,
492 LONG pat0, LONG pat1)
494 NV04EXASetPattern(carddata, clr0, clr1, pat0, pat1);
497 /* NOTE: Assumes lock on bitmap is already made */
498 /* NOTE: Assumes buffer is not mapped */
499 BOOL HIDDNouveauNV04FillSolidRect(struct CardData * carddata,
500 struct HIDDNouveauBitMapData * bmdata, LONG minX, LONG minY, LONG maxX,
501 LONG maxY, ULONG drawmode, ULONG color)
503 if (NV04EXAPrepareSolid(bmdata, drawmode, ~0, color))
505 NV04EXASolid(bmdata, minX, minY, maxX + 1, maxY + 1);
506 return TRUE;
509 return FALSE;
512 /* NOTE: Assumes lock on bitmap is already made */
513 /* NOTE: Assumes buffer is not mapped */
514 BOOL HIDDNouveauNV04CopySameFormat(struct CardData * carddata,
515 struct HIDDNouveauBitMapData * srcdata, struct HIDDNouveauBitMapData * destdata,
516 LONG srcX, LONG srcY, LONG destX, LONG destY, LONG width, LONG height,
517 ULONG drawmode)
519 if (NV04EXAPrepareCopy(srcdata, destdata, 0, 0, drawmode, ~0))
521 NV04EXACopy(destdata, srcX, srcY, destX, destY, width, height);
522 return TRUE;
525 return FALSE;