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.
24 #include <kdrive-config.h>
28 #include "g400_common.h"
31 static PicturePtr currentSrcPicture
;
32 static PicturePtr currentMaskPicture
;
33 static PixmapPtr currentSrc
;
34 static PixmapPtr currentMask
;
46 static struct blendinfo mgaBlendOP
[] = {
48 {0, 0, MGA_SRC_ZERO
| MGA_DST_ZERO
},
50 {0, 0, MGA_SRC_ONE
| MGA_DST_ZERO
},
52 {0, 0, MGA_SRC_ZERO
| MGA_DST_ONE
},
54 {0, 1, MGA_SRC_ONE
| MGA_DST_ONE_MINUS_SRC_ALPHA
},
56 {1, 0, MGA_SRC_ONE_MINUS_DST_ALPHA
| MGA_DST_ONE
},
58 {1, 0, MGA_SRC_DST_ALPHA
| MGA_DST_ZERO
},
60 {0, 1, MGA_SRC_ZERO
| MGA_DST_SRC_ALPHA
},
62 {1, 0, MGA_SRC_ONE_MINUS_DST_ALPHA
| MGA_DST_ZERO
},
64 {0, 1, MGA_SRC_ZERO
| MGA_DST_ONE_MINUS_SRC_ALPHA
},
66 {1, 1, MGA_SRC_DST_ALPHA
| MGA_DST_ONE_MINUS_SRC_ALPHA
},
68 {1, 1, MGA_SRC_ONE_MINUS_DST_ALPHA
| MGA_DST_SRC_ALPHA
},
70 {1, 1, MGA_SRC_ONE_MINUS_DST_ALPHA
| MGA_DST_ONE_MINUS_SRC_ALPHA
},
72 {0, 0, MGA_SRC_ONE
| MGA_DST_ONE
},
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
},
99 return ((1 << (ret
-1)) == val
) ? (ret
-1) : ret
;
104 mgaCheckSourceTexture (int tmu
,
107 int w
= pPict
->pDrawable
->width
;
108 int h
= pPict
->pDrawable
->height
;
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
;
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
));
136 PrepareSourceTexture (int tmu
,
137 PicturePtr pSrcPicture
,
140 KdScreenPriv (pSrc
->drawable
.pScreen
);
141 int mem_base
=(int)pScreenPriv
->screen
->memory_base
;
142 int pitch
= pSrc
->devKind
/ (pSrc
->drawable
.bitsPerPixel
>> 3);
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
;
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
;
162 if (PICT_FORMAT_A(pSrcPicture
->format
) != 0) {
165 texctl
|= MGA_TAMASK
| MGA_TAKEY
;
168 if (pSrcPicture
->repeat
) {
169 texctl
&= ~MGA_CLAMPUV
;
173 texctl2
|= MGA_TC2_DUALTEX
| MGA_TC2_SELECT_TMU1
| flags
;
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
);
187 MGA_OUT32 (mmio
, MGA_REG_TEXFILTER
,
188 (0x10<<21) | MGA_MAG_NRST
| MGA_MIN_NRST
);
193 MGA_OUT32 (mmio
, MGA_REG_TEXCTL2
, MGA_G400_TC2_MAGIC
| MGA_TC2_DUALTEX
| flags
);
201 * The formals params are the elements of the following matrix:
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
213 setTMIncrementsRegs(int X_incx
,
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 */
229 X_incx
= X_incx
<< decalw
;
230 X_incy
= X_incy
<< decalw
;
231 X_init
= X_init
<< 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 */
241 Y_incx
= Y_incx
<< decalh
;
242 Y_incy
= Y_incy
<< decalh
;
243 Y_init
= Y_init
<< decalh
;
246 Y_incx
= Y_incx
>> decalh
;
247 Y_incy
= Y_incy
>> decalh
;
248 Y_init
= Y_init
>> decalh
;
251 /* Set TM registers */
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
);
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
))
276 if (pMaskPicture
!= NULL
) {
277 if (PICT_FORMAT_A(pMaskPicture
->format
) == 0)
278 MGA_FALLBACK(("Mask without alpha unsupported"));
279 if (!mgaCheckSourceTexture (1, pMaskPicture
))
283 if (pMaskPicture
->componentAlpha
)
284 MGA_FALLBACK(("Component alpha unsupported"));
286 if (pDstPicture
->format
== PICT_a8
)
287 MGA_FALLBACK(("render to A8 unsupported"));
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
313 mgaPrepareComposite (int op
,
314 PicturePtr pSrcPicture
,
315 PicturePtr pMaskPicture
,
316 PicturePtr pDstPicture
,
321 KdScreenPriv (pSrc
->drawable
.pScreen
);
322 int mem_base
=(int)pScreenPriv
->screen
->memory_base
;
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 */
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
;
342 if (!PrepareSourceTexture (1, pMaskPicture
, pMask
)) return FALSE
;
345 /* Prepare multi-texture registers */
348 if (pSrcPicture
->format
== PICT_a8
) {
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 */
359 if (!PrepareSourceTexture (1, pSrcPicture
, pSrc
)) return FALSE
;
360 ds1
=C_ARG2_PREV
| COLOR_ARG2
|
361 A_ARG2_PREV
| ALPHA_ARG2
;
365 ds0
=C_ARG1_CUR
| COLOR_ARG1
|
366 A_ARG1_CUR
| ALPHA_ARG1
;
370 /* As or Am might be NULL. in this case we don't multiply because,
371 * the alpha component holds garbage.
374 if (PICT_FORMAT_A (pMaskPicture
->format
) == 0) {
376 color
= C_ARG2_PREV
| COLOR_ARG2
;
379 color
= C_ARG1_ALPHA
| C_ARG2_PREV
| COLOR_MUL
;
382 if (PICT_FORMAT_A (pMaskPicture
->format
) == 0) {
384 alpha
= A_ARG2_PREV
| ALPHA_ARG2
;
385 } else if (PICT_FORMAT_A (pSrcPicture
->format
) == 0) {
387 alpha
= A_ARG1_CUR
| ALPHA_ARG1
;
390 alpha
= A_ARG1_CUR
| A_ARG2_PREV
| ALPHA_MUL
;
396 /* MultiTexture modulation */
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
|
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
;
415 MGA_OUT32 (mmio
, MGA_REG_DWGCTL
, cmd
);
416 MGA_OUT32 (mmio
, MGA_REG_ALPHACTRL
, MGA_ALPHACHANNEL
| blendcntl
);
418 currentSrcPicture
= pSrcPicture
;
419 currentMaskPicture
= pMaskPicture
;
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
);
432 mgaComposite (int srcX
,
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] +
454 currentSrcPicture
->transform
->matrix
[1][0],
455 currentSrcPicture
->transform
->matrix
[1][1],
456 currentSrcPicture
->transform
->matrix
[1][2] +
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
);
463 setTMIncrementsRegs (1 << 16, 0, srcX
<< 16,
464 0, 1 << 16, srcY
<< 16,
466 20-src_w2
, 20-src_h2
);
469 if (currentMask
!= NULL
) {
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] +
478 currentMaskPicture
->transform
->matrix
[1][0],
479 currentMaskPicture
->transform
->matrix
[1][1],
480 currentMaskPicture
->transform
->matrix
[1][2] +
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
);
487 setTMIncrementsRegs (1 << 16, 0, maskX
<< 16,
488 0, 1 << 16, maskY
<< 16,
490 20-mask_w2
, 20-mask_h2
);
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)
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));
508 mgaDoneComposite (void)