First import
[xorg_rtime.git] / xorg-server-1.4 / hw / kdrive / mga / g400_composite.c
blobdda9d9347a00aa85cfc27c964655d05a4e5c0ac0
1 /*
2 * Copyright © 2004 Damien Ciabrini
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Anders Carlsson not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Anders Carlsson makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
14 * DAMIEN CIABRINI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ANDERS CARLSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
23 #ifdef HAVE_CONFIG_H
24 #include <kdrive-config.h>
25 #endif
27 #include "mga.h"
28 #include "g400_common.h"
31 static PicturePtr currentSrcPicture;
32 static PicturePtr currentMaskPicture;
33 static PixmapPtr currentSrc;
34 static PixmapPtr currentMask;
35 static int src_w2;
36 static int src_h2;
37 static int mask_w2;
38 static int mask_h2;
40 struct blendinfo {
41 Bool dst_alpha;
42 Bool src_alpha;
43 CARD32 blend_cntl;
46 static struct blendinfo mgaBlendOP[] = {
47 /* Clear */
48 {0, 0, MGA_SRC_ZERO | MGA_DST_ZERO},
49 /* Src */
50 {0, 0, MGA_SRC_ONE | MGA_DST_ZERO},
51 /* Dst */
52 {0, 0, MGA_SRC_ZERO | MGA_DST_ONE},
53 /* Over */
54 {0, 1, MGA_SRC_ONE | MGA_DST_ONE_MINUS_SRC_ALPHA},
55 /* OverReverse */
56 {1, 0, MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_ONE},
57 /* In */
58 {1, 0, MGA_SRC_DST_ALPHA | MGA_DST_ZERO},
59 /* InReverse */
60 {0, 1, MGA_SRC_ZERO | MGA_DST_SRC_ALPHA},
61 /* Out */
62 {1, 0, MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_ZERO},
63 /* OutReverse */
64 {0, 1, MGA_SRC_ZERO | MGA_DST_ONE_MINUS_SRC_ALPHA},
65 /* Atop */
66 {1, 1, MGA_SRC_DST_ALPHA | MGA_DST_ONE_MINUS_SRC_ALPHA},
67 /* AtopReverse */
68 {1, 1, MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_SRC_ALPHA},
69 /* Xor */
70 {1, 1, MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_ONE_MINUS_SRC_ALPHA},
71 /* Add */
72 {0, 0, MGA_SRC_ONE | MGA_DST_ONE},
75 struct formatinfo {
76 int fmt;
77 CARD32 card_fmt;
80 static struct formatinfo texformats[] = {
81 {PICT_a8r8g8b8, MGA_TW32},
82 {PICT_x8r8g8b8, MGA_TW32},
83 {PICT_r5g6b5, MGA_TW16},
84 {PICT_a1r5g5b5, MGA_TW15},
85 {PICT_x1r5g5b5, MGA_TW15},
86 {PICT_a4r4g4b4, MGA_TW12},
87 {PICT_x4r4g4b4, MGA_TW12},
88 {PICT_a8, MGA_TW8A},
91 static int
92 MGA_LOG2( int val )
94 int ret = 0;
95 if (val==1) return 0;
96 while (val >> ret)
97 ret++;
99 return ((1 << (ret-1)) == val) ? (ret-1) : ret;
103 static Bool
104 mgaCheckSourceTexture (int tmu,
105 PicturePtr pPict)
107 int w = pPict->pDrawable->width;
108 int h = pPict->pDrawable->height;
109 int i;
110 CARD32 texctl = 0;
112 if ((w > 2047) || (h > 2047))
113 MGA_FALLBACK(("Picture w/h too large (%dx%d)\n", w, h));
115 for (i = 0; i < sizeof(texformats) / sizeof(texformats[0]); i++) {
116 if (texformats[i].fmt == pPict->format) {
117 texctl = texformats[i].card_fmt;
118 break;
121 if (texctl == 0) {
122 MGA_FALLBACK(("Unsupported picture format 0x%x\n", pPict->format));
125 if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0))
126 MGA_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w, h));
128 if (pPict->filter != PictFilterNearest &&
129 pPict->filter != PictFilterBilinear)
130 MGA_FALLBACK(("Unsupported filter 0x%x\n", pPict->filter));
132 return TRUE;
135 static Bool
136 PrepareSourceTexture (int tmu,
137 PicturePtr pSrcPicture,
138 PixmapPtr pSrc)
140 KdScreenPriv (pSrc->drawable.pScreen);
141 int mem_base=(int)pScreenPriv->screen->memory_base;
142 int pitch = pSrc->devKind / (pSrc->drawable.bitsPerPixel >> 3);
143 int i;
145 int w = pSrc->drawable.width;
146 int h = pSrc->drawable.height;
147 int w_log2 = MGA_LOG2(w);
148 int h_log2 = MGA_LOG2(h);
150 int texctl = MGA_PITCHLIN | ((pitch & (2048 - 1)) << 9) |
151 MGA_CLAMPUV | MGA_NOPERSPECTIVE;
152 int flags = 0;
153 int texctl2 = MGA_G400_TC2_MAGIC | flags;
155 for (i = 0; i < sizeof(texformats) / sizeof(texformats[0]); i++) {
156 if (texformats[i].fmt == pSrcPicture->format) {
157 texctl |= texformats[i].card_fmt;
158 break;
162 if (PICT_FORMAT_A(pSrcPicture->format) != 0) {
163 texctl |= MGA_TAKEY;
164 } else {
165 texctl |= MGA_TAMASK | MGA_TAKEY;
168 if (pSrcPicture->repeat) {
169 texctl &= ~MGA_CLAMPUV;
172 if (tmu == 1)
173 texctl2 |= MGA_TC2_DUALTEX | MGA_TC2_SELECT_TMU1 | flags;
175 mgaWaitAvail (6);
176 MGA_OUT32 (mmio, MGA_REG_TEXCTL2, texctl2);
177 MGA_OUT32 (mmio, MGA_REG_TEXCTL, texctl);
178 /* Source (texture) address + pitch */
179 MGA_OUT32 (mmio, MGA_REG_TEXORG, ((int)pSrc->devPrivate.ptr - mem_base));
180 MGA_OUT32 (mmio, MGA_REG_TEXWIDTH, (w-1)<<18 | ((8-w_log2)&63)<<9 | w_log2);
181 MGA_OUT32 (mmio, MGA_REG_TEXHEIGHT, (h-1)<<18 | ((8-h_log2)&63)<<9 | h_log2);
182 /* Set blit filtering flags */
183 if (pSrcPicture->filter == PictFilterBilinear) {
184 MGA_OUT32 (mmio, MGA_REG_TEXFILTER,
185 (0x10<<21) | MGA_MAG_BILIN | MGA_MIN_BILIN);
186 } else {
187 MGA_OUT32 (mmio, MGA_REG_TEXFILTER,
188 (0x10<<21) | MGA_MAG_NRST | MGA_MIN_NRST);
191 if (tmu == 1) {
192 mgaWaitAvail (1);
193 MGA_OUT32 (mmio, MGA_REG_TEXCTL2, MGA_G400_TC2_MAGIC | MGA_TC2_DUALTEX | flags);
196 return TRUE;
201 * The formals params are the elements of the following matrix:
203 * Dest Transform Src
204 * coords coords
205 * / Xdst \ / X_incx X_incy X_init \ / Xsrc \
206 * | Ydst | = | Y_incx Y_incy Y_init | x | Ysrc |
207 * \ 1 / \ H_incx H_incy H_init / \ 1 /
209 * matrix elements are 32bits fixed points (16.16)
210 * mga_fx_* is the size of the fixed point for the TMU
212 static void
213 setTMIncrementsRegs(int X_incx,
214 int X_incy,
215 int X_init,
216 int Y_incx,
217 int Y_incy,
218 int Y_init,
219 int H_incx,
220 int H_incy,
221 int H_init,
222 int mga_fx_width_size,
223 int mga_fx_height_size) {
224 int decalw = mga_fx_width_size - 16;
225 int decalh = mga_fx_height_size - 16;
227 /* Convert 16 bits fixpoint -> MGA variable size fixpoint */
228 if (decalw >= 0) {
229 X_incx = X_incx << decalw;
230 X_incy = X_incy << decalw;
231 X_init = X_init << decalw;
232 } else {
233 decalw =- decalw;
234 X_incx = X_incx >> decalw;
235 X_incy = X_incy >> decalw;
236 X_init = X_init >> decalw;
239 /* Convert 16 bits fixpoint -> MGA variable size fixpoint */
240 if (decalh >= 0) {
241 Y_incx = Y_incx << decalh;
242 Y_incy = Y_incy << decalh;
243 Y_init = Y_init << decalh;
244 } else {
245 decalh =- decalh;
246 Y_incx = Y_incx >> decalh;
247 Y_incy = Y_incy >> decalh;
248 Y_init = Y_init >> decalh;
251 /* Set TM registers */
252 mgaWaitAvail (9);
253 MGA_OUT32 (mmio, MGA_REG_TMR0, X_incx);
254 MGA_OUT32 (mmio, MGA_REG_TMR1, Y_incx);
255 MGA_OUT32 (mmio, MGA_REG_TMR2, X_incy);
256 MGA_OUT32 (mmio, MGA_REG_TMR3, Y_incy);
257 MGA_OUT32 (mmio, MGA_REG_TMR4, H_incx);
258 MGA_OUT32 (mmio, MGA_REG_TMR5, H_incy);
259 MGA_OUT32 (mmio, MGA_REG_TMR6, X_init);
260 MGA_OUT32 (mmio, MGA_REG_TMR7, Y_init);
261 MGA_OUT32 (mmio, MGA_REG_TMR8, H_init);
267 Bool
268 mgaCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
269 PicturePtr pDstPicture)
271 if (op >= sizeof(mgaBlendOP) / sizeof(mgaBlendOP[0]))
272 MGA_FALLBACK(("unsupported op %x", op));
273 if (!mgaCheckSourceTexture (0, pSrcPicture))
274 return FALSE;
276 if (pMaskPicture != NULL) {
277 if (PICT_FORMAT_A(pMaskPicture->format) == 0)
278 MGA_FALLBACK(("Mask without alpha unsupported"));
279 if (!mgaCheckSourceTexture (1, pMaskPicture))
280 return FALSE;
283 if (pMaskPicture->componentAlpha)
284 MGA_FALLBACK(("Component alpha unsupported"));
286 if (pDstPicture->format == PICT_a8)
287 MGA_FALLBACK(("render to A8 unsupported"));
289 return TRUE;
292 #define C_ARG1_CUR 0x0
293 #define C_ARG1_ALPHA MGA_TDS_COLOR_ARG1_REPLICATEALPHA
294 #define C_ARG2_DIFFUSE MGA_TDS_COLOR_ARG2_DIFFUSE
295 #define C_ARG2_FCOL MGA_TDS_COLOR_ARG2_FCOL
296 #define C_ARG2_PREV MGA_TDS_COLOR_ARG2_PREVSTAGE
297 #define C_ARG1_INV MGA_TDS_COLOR_ARG1_INV
298 #define C_ARG2_INV MGA_TDS_COLOR_ARG2_INV
299 #define COLOR_MUL MGA_TDS_COLOR_SEL_MUL
300 #define COLOR_ARG1 MGA_TDS_COLOR_SEL_ARG1
301 #define COLOR_ARG2 MGA_TDS_COLOR_SEL_ARG2
302 #define A_ARG1_CUR 0x0
303 #define A_ARG2_IGN A_ARG2_DIFFUSE
304 #define A_ARG2_FCOL MGA_TDS_ALPHA_ARG2_FCOL
305 #define A_ARG2_DIFFUSE MGA_TDS_ALPHA_ARG2_DIFFUSE
306 #define A_ARG2_PREV MGA_TDS_ALPHA_ARG2_PREVSTAGE
307 #define ALPHA_MUL MGA_TDS_ALPHA_SEL_MUL
308 #define ALPHA_ARG1 MGA_TDS_ALPHA_SEL_ARG1
309 #define ALPHA_ARG2 MGA_TDS_ALPHA_SEL_ARG2
312 Bool
313 mgaPrepareComposite (int op,
314 PicturePtr pSrcPicture,
315 PicturePtr pMaskPicture,
316 PicturePtr pDstPicture,
317 PixmapPtr pSrc,
318 PixmapPtr pMask,
319 PixmapPtr pDst)
321 KdScreenPriv (pSrc->drawable.pScreen);
322 int mem_base=(int)pScreenPriv->screen->memory_base;
323 int cmd, blendcntl;
324 int ds0, ds1;
326 /* Init MGA (clipping) */
327 mgaSetup (pSrc->drawable.pScreen, pDst->drawable.bitsPerPixel, 1);
329 /* Initialize fg color to 0, used in the src = A8 case */
330 MGA_OUT32 (mmio, MGA_REG_FCOL, 0xff000000);
332 /* Destination flags */
333 mgaWaitAvail (2);
334 MGA_OUT32 (mmio, MGA_REG_DSTORG, ((int)pDst->devPrivate.ptr - mem_base));
335 MGA_OUT32 (mmio, MGA_REG_PITCH,
336 pDst->devKind / (pDst->drawable.bitsPerPixel >> 3));
339 /* Source(s) flags */
340 if (!PrepareSourceTexture (0, pSrcPicture, pSrc)) return FALSE;
341 if (pMask != NULL) {
342 if (!PrepareSourceTexture (1, pMaskPicture, pMask)) return FALSE;
345 /* Prepare multi-texture registers */
346 ds0=ds1=0;
348 if (pSrcPicture->format == PICT_a8) {
349 /* C = 0 A = As */
350 /* MGA HW: A8 format makes RGB white. We use FCOL for the black
351 * If FCOL was not 0, it would have been be premultiplied (RENDER)
352 * color component would have been:
353 * C_ARG1_ALPHA | C_ARG2_FCOL | COLOR_MUL
355 ds0=C_ARG2_FCOL | COLOR_ARG2 |
356 A_ARG1_CUR | ALPHA_ARG1;
357 /* MGA HW: TMU1 must be enabled when DUALSTAGE0 contains something */
358 if (pMask == NULL) {
359 if (!PrepareSourceTexture (1, pSrcPicture, pSrc)) return FALSE;
360 ds1=C_ARG2_PREV | COLOR_ARG2 |
361 A_ARG2_PREV | ALPHA_ARG2;
363 } else {
364 /* C = Cs A = As */
365 ds0=C_ARG1_CUR | COLOR_ARG1 |
366 A_ARG1_CUR | ALPHA_ARG1;
369 if (pMask != NULL) {
370 /* As or Am might be NULL. in this case we don't multiply because,
371 * the alpha component holds garbage.
373 int color,alpha;
374 if (PICT_FORMAT_A (pMaskPicture->format) == 0) {
375 /* C = Cs */
376 color = C_ARG2_PREV | COLOR_ARG2;
377 } else {
378 /* C = Am * Cs */
379 color = C_ARG1_ALPHA | C_ARG2_PREV | COLOR_MUL;
382 if (PICT_FORMAT_A (pMaskPicture->format) == 0) {
383 /* A = As */
384 alpha = A_ARG2_PREV | ALPHA_ARG2;
385 } else if (PICT_FORMAT_A (pSrcPicture->format) == 0) {
386 /* A = Am */
387 alpha = A_ARG1_CUR | ALPHA_ARG1;
388 } else {
389 /* A = Am * As */
390 alpha = A_ARG1_CUR | A_ARG2_PREV | ALPHA_MUL;
393 ds1 = color | alpha;
396 /* MultiTexture modulation */
397 mgaWaitAvail (2);
398 MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE0, ds0);
399 MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE1, ds1);
402 cmd = MGA_OPCOD_TEXTURE_TRAP | MGA_ATYPE_RSTR | 0x000c0000 |
403 MGA_DWGCTL_SHIFTZERO | MGA_DWGCTL_SGNZERO | MGA_DWGCTL_ARZERO |
404 MGA_ATYPE_I;
406 blendcntl = mgaBlendOP[op].blend_cntl;
407 if (PICT_FORMAT_A(pDstPicture->format) == 0 && mgaBlendOP[op].dst_alpha) {
408 if ((blendcntl & MGA_SRC_BLEND_MASK) == MGA_SRC_DST_ALPHA)
409 blendcntl = (blendcntl & ~MGA_SRC_BLEND_MASK) | MGA_SRC_ONE;
410 else if ((blendcntl & MGA_SRC_BLEND_MASK) == MGA_SRC_ONE_MINUS_DST_ALPHA)
411 blendcntl = (blendcntl & ~MGA_SRC_BLEND_MASK) | MGA_SRC_ZERO;
414 mgaWaitAvail (2);
415 MGA_OUT32 (mmio, MGA_REG_DWGCTL, cmd);
416 MGA_OUT32 (mmio, MGA_REG_ALPHACTRL, MGA_ALPHACHANNEL | blendcntl);
418 currentSrcPicture = pSrcPicture;
419 currentMaskPicture = pMaskPicture;
420 currentSrc = pSrc;
421 currentMask = pMask;
422 src_w2 = MGA_LOG2 (currentSrc->drawable.width);
423 src_h2 = MGA_LOG2 (currentSrc->drawable.height);
424 mask_w2 = MGA_LOG2 (currentMask->drawable.width);
425 mask_h2 = MGA_LOG2 (currentMask->drawable.height);
427 return TRUE;
431 void
432 mgaComposite (int srcX,
433 int srcY,
434 int maskX,
435 int maskY,
436 int dstX,
437 int dstY,
438 int width,
439 int height)
441 /* Source positions can be outside source textures' boundaries.
442 * We clamp the values here to avoid rendering glitches.
444 srcX=srcX % currentSrc->drawable.width;
445 srcY=srcY % currentSrc->drawable.height;
446 maskX=maskX % currentMask->drawable.width;
447 maskY=maskY % currentMask->drawable.height;
449 if (currentSrcPicture->transform) {
450 setTMIncrementsRegs (currentSrcPicture->transform->matrix[0][0],
451 currentSrcPicture->transform->matrix[0][1],
452 currentSrcPicture->transform->matrix[0][2] +
453 (srcX << 16),
454 currentSrcPicture->transform->matrix[1][0],
455 currentSrcPicture->transform->matrix[1][1],
456 currentSrcPicture->transform->matrix[1][2] +
457 (srcY << 16),
458 currentSrcPicture->transform->matrix[2][0],
459 currentSrcPicture->transform->matrix[2][1],
460 currentSrcPicture->transform->matrix[2][2],
461 20-src_w2, 20-src_h2);
462 } else {
463 setTMIncrementsRegs (1 << 16, 0, srcX << 16,
464 0, 1 << 16, srcY << 16,
465 0, 0, 0x10000,
466 20-src_w2, 20-src_h2);
469 if (currentMask != NULL) {
470 mgaWaitAvail (1);
471 MGA_OUT32 (mmio, MGA_REG_TEXCTL2,
472 MGA_G400_TC2_MAGIC | MGA_TC2_DUALTEX | MGA_TC2_SELECT_TMU1);
473 if (currentMaskPicture->transform) {
474 setTMIncrementsRegs (currentMaskPicture->transform->matrix[0][0],
475 currentMaskPicture->transform->matrix[0][1],
476 currentMaskPicture->transform->matrix[0][2] +
477 (maskX << 16),
478 currentMaskPicture->transform->matrix[1][0],
479 currentMaskPicture->transform->matrix[1][1],
480 currentMaskPicture->transform->matrix[1][2] +
481 (maskY << 16),
482 currentMaskPicture->transform->matrix[2][0],
483 currentMaskPicture->transform->matrix[2][1],
484 currentMaskPicture->transform->matrix[2][2],
485 20-mask_w2, 20-mask_h2);
486 } else {
487 setTMIncrementsRegs (1 << 16, 0, maskX << 16,
488 0, 1 << 16, maskY << 16,
489 0, 0, 0x10000,
490 20-mask_w2, 20-mask_h2);
493 mgaWaitAvail (1);
494 MGA_OUT32 (mmio, MGA_REG_TEXCTL2, MGA_G400_TC2_MAGIC | MGA_TC2_DUALTEX);
497 /* Destination Bounding Box
498 * (Boundary Right | Boundary Left, Y dest | Height)
500 mgaWaitAvail (2);
501 MGA_OUT32 (mmio, MGA_REG_FXBNDRY,
502 ((dstX + width) << 16) | (dstX & 0xffff));
503 MGA_OUT32 (mmio, MGA_REG_YDSTLEN | MGA_REG_EXEC,
504 (dstY << 16) | (height & 0xffff));
507 void
508 mgaDoneComposite (void)