summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-04-23 14:49:22 +1000
committerBen Skeggs <bskeggs@redhat.com>2012-04-24 11:56:05 +1000
commitb09a61780ea6710b679a6a099e35987e7a5f559f (patch)
tree601e218f2b32d61c5ac0aead286b693496920b59
parent9583753a205c585ec844dfb7168513a2c2a157ba (diff)
nv10/exa: implement support for solid pictures
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--src/nv10_exa.c197
1 files changed, 81 insertions, 116 deletions
diff --git a/src/nv10_exa.c b/src/nv10_exa.c
index b562e97..2da8cf6 100644
--- a/src/nv10_exa.c
+++ b/src/nv10_exa.c
@@ -66,11 +66,8 @@ static struct pict_format {
};
static int
-get_tex_format(PicturePtr pict)
+get_tex_format(NVPtr pNv, PicturePtr pict)
{
- ScrnInfoPtr pScrn = xf86Screens[pict->pDrawable->pScreen->myNum];
- NVPtr pNv = NVPTR(pScrn);
-
/* If repeat is set we're always handling a 1x1 texture with
* ARGB/XRGB destination, in that case we change the format to
* use the POT (swizzled) matching format.
@@ -145,20 +142,22 @@ effective_component_alpha(PicturePtr mask)
}
static Bool
-check_texture(PicturePtr pict)
+check_texture(NVPtr pNv, PicturePtr pict)
{
- int w, h;
+ int w = 1, h = 1;
- if (!pict->pDrawable)
- NOUVEAU_FALLBACK("Solid and gradient pictures unsupported\n");
-
- w = pict->pDrawable->width;
- h = pict->pDrawable->height;
+ if (pict->pDrawable) {
+ w = pict->pDrawable->width;
+ h = pict->pDrawable->height;
+ } else {
+ if (pict->pSourcePict->type != SourcePictTypeSolidFill)
+ NOUVEAU_FALLBACK("gradient pictures unsupported\n");
+ }
if (w > 2046 || h > 2046)
NOUVEAU_FALLBACK("picture too large, %dx%d\n", w, h);
- if (!get_tex_format(pict))
+ if (!get_tex_format(pNv, pict))
return FALSE;
if (pict->filter != PictFilterNearest &&
@@ -338,6 +337,9 @@ print_fallback_info(char *reason, int op, PicturePtr src, PicturePtr mask,
Bool
NV10EXACheckComposite(int op, PicturePtr src, PicturePtr mask, PicturePtr dst)
{
+ ScrnInfoPtr pScrn = xf86Screens[dst->pDrawable->pScreen->myNum];
+ NVPtr pNv = NVPTR(pScrn);
+
if (!check_pict_op(op)) {
print_fallback_info("pictop", op, src, mask, dst);
return FALSE;
@@ -348,13 +350,13 @@ NV10EXACheckComposite(int op, PicturePtr src, PicturePtr mask, PicturePtr dst)
return FALSE;
}
- if (!check_texture(src)) {
+ if (!check_texture(pNv, src)) {
print_fallback_info("src", op, src, mask, dst);
return FALSE;
}
if (mask) {
- if (!check_texture(mask)) {
+ if (!check_texture(pNv, mask)) {
print_fallback_info("mask", op, src,
mask, dst);
return FALSE;
@@ -386,7 +388,7 @@ setup_texture(NVPtr pNv, int unit, PicturePtr pict, PixmapPtr pixmap)
NV10_3D_TEX_FORMAT_WRAP_S_CLAMP_TO_EDGE |
log2i(w) << 20 | log2i(h) << 16 |
1 << 12 | /* lod == 1 */
- get_tex_format(pict) |
+ get_tex_format(pNv, pict) |
0x50 /* UNK */;
/* NPOT_SIZE expects an even number for width, we can round up uneven
@@ -458,96 +460,6 @@ setup_render_target(NVPtr pNv, PicturePtr pict, PixmapPtr pixmap)
return TRUE;
}
-/*
- * This can be a bit difficult to understand at first glance. Reg
- * combiners are described here:
- * http://icps.u-strasbg.fr/~marchesin/perso/extensions/NV/register_combiners.html
- *
- * Single texturing setup, without honoring vertex colors (non default
- * setup) is: Alpha RC 0 : a_0 * 1 + 0 * 0 RGB RC 0 : rgb_0 * 1 + 0 *
- * 0 RC 1s are unused Final combiner uses default setup
- *
- * Default setup uses vertex rgb/alpha in place of 1s above, but we
- * don't need that in 2D.
- *
- * Multi texturing setup, where we do TEX0 in TEX1 (masking) is:
- * Alpha RC 0 : a_0 * a_1 + 0 * 0
- * RGB RC0 : rgb_0 * a_1 + 0 * 0
- * RC 1s are unused
- * Final combiner uses default setup
- */
-
-/* Bind the combiner variable <input> to a constant 1. */
-#define RC_IN_ONE(input) \
- (NV10_3D_RC_IN_RGB_##input##_INPUT_ZERO | \
- NV10_3D_RC_IN_RGB_##input##_COMPONENT_USAGE_ALPHA | \
- NV10_3D_RC_IN_RGB_##input##_MAPPING_UNSIGNED_INVERT)
-
-/* Bind the combiner variable <input> to the specified channel from
- * the texture unit <unit>. */
-#define RC_IN_TEX(input, chan, unit) \
- (NV10_3D_RC_IN_RGB_##input##_INPUT_TEXTURE##unit | \
- NV10_3D_RC_IN_RGB_##input##_COMPONENT_USAGE_##chan)
-
-/* Bind the combiner variable <input> to the specified channel from
- * the constant color <unit>. */
-#define RC_IN_COLOR(input, chan, unit) \
- (NV10_3D_RC_IN_RGB_##input##_INPUT_CONSTANT_COLOR##unit | \
- NV10_3D_RC_IN_RGB_##input##_COMPONENT_USAGE_##chan)
-
-static void
-setup_combiners(NVPtr pNv, PicturePtr src, PicturePtr mask, int alu)
-{
- struct nouveau_pushbuf *push = pNv->pushbuf;
- uint32_t rc_in_alpha = 0, rc_in_rgb = 0;
-
- if (PICT_FORMAT_A(src->format))
- rc_in_alpha |= RC_IN_TEX(A, ALPHA, 0);
- else
- rc_in_alpha |= RC_IN_ONE(A);
-
- if (mask && PICT_FORMAT_A(mask->format))
- rc_in_alpha |= RC_IN_TEX(B, ALPHA, 1);
- else
- rc_in_alpha |= RC_IN_ONE(B);
-
- if (effective_component_alpha(mask)) {
- if (!needs_src_alpha(alu)) {
- /* The alpha channels won't be used for blending. Drop
- * them, as our pixels only have 4 components...
- * output_i = src_i * mask_i
- */
- if (PICT_FORMAT_RGB(src->format))
- rc_in_rgb |= RC_IN_TEX(A, RGB, 0);
- } else {
- /* The RGB channels won't be used for blending. Drop
- * them.
- * output_i = src_alpha * mask_i
- */
- if (PICT_FORMAT_A(src->format))
- rc_in_rgb |= RC_IN_TEX(A, ALPHA, 0);
- else
- rc_in_rgb |= RC_IN_ONE(A);
- }
-
- rc_in_rgb |= RC_IN_TEX(B, RGB, 1);
-
- } else {
- if (PICT_FORMAT_RGB(src->format))
- rc_in_rgb |= RC_IN_TEX(A, RGB, 0);
-
- if (mask && PICT_FORMAT_A(mask->format))
- rc_in_rgb |= RC_IN_TEX(B, ALPHA, 1);
- else
- rc_in_rgb |= RC_IN_ONE(B);
- }
-
- BEGIN_NV04(push, NV10_3D(RC_IN_ALPHA(0)), 1);
- PUSH_DATA (push, rc_in_alpha);
- BEGIN_NV04(push, NV10_3D(RC_IN_RGB(0)), 1);
- PUSH_DATA (push, rc_in_rgb);
-}
-
static void
setup_blend_function(NVPtr pNv, PicturePtr pdpict, int alu)
{
@@ -578,6 +490,52 @@ setup_blend_function(NVPtr pNv, PicturePtr pdpict, int alu)
PUSH_DATA (push, 1);
}
+#define RCSRC_COL(i) (0x01 + (unit))
+#define RCSRC_TEX(i) (0x08 + (unit))
+#define RCSEL_COLOR (0x00)
+#define RCSEL_ALPHA (0x10)
+#define RCINP_ZERO (0x00)
+#define RCINP_ONE (0x20)
+#define RCINP_A__SHIFT 24
+#define RCINP_B__SHIFT 16
+
+static Bool
+setup_picture(NVPtr pNv, PicturePtr pict, PixmapPtr pixmap, int unit,
+ uint32_t *color, uint32_t *alpha)
+{
+ struct nouveau_pushbuf *push = pNv->pushbuf;
+ uint32_t shift, source;
+
+ if (pict && pict->pDrawable) {
+ if (!setup_texture(pNv, unit, pict, pixmap))
+ return FALSE;
+ source = RCSRC_TEX(unit);
+ } else
+ if (pict) {
+ BEGIN_NV04(push, NV10_3D(RC_COLOR(unit)), 1);
+ PUSH_DATA (push, pict->pSourcePict->solidFill.color);
+ source = RCSRC_COL(unit);
+ }
+
+ if (pict && PICT_FORMAT_RGB(pict->format))
+ *color = RCSEL_COLOR | source;
+ else
+ *color = RCSEL_ALPHA | RCINP_ZERO;
+
+ if (pict && PICT_FORMAT_A(pict->format))
+ *alpha = RCSEL_ALPHA | source;
+ else
+ *alpha = RCSEL_ALPHA | RCINP_ONE;
+
+ if (unit)
+ shift = RCINP_B__SHIFT;
+ else
+ shift = RCINP_A__SHIFT;
+ *color <<= shift;
+ *alpha <<= shift;
+ return TRUE;
+}
+
Bool
NV10EXAPrepareComposite(int op,
PicturePtr pict_src,
@@ -590,28 +548,35 @@ NV10EXAPrepareComposite(int op,
ScrnInfoPtr pScrn = xf86Screens[dst->drawable.pScreen->myNum];
NVPtr pNv = NVPTR(pScrn);
struct nouveau_pushbuf *push = pNv->pushbuf;
+ uint32_t sc, sa, mc, ma;
if (!PUSH_SPACE(push, 128))
return FALSE;
PUSH_RESET(push);
- /* Set dst format */
+ /* setup render target and blending */
if (!setup_render_target(pNv, pict_dst, dst))
return FALSE;
+ setup_blend_function(pNv, pict_dst, op);
- /* Set src format */
- if (!setup_texture(pNv, 0, pict_src, src))
+ /* select picture sources */
+ if (!setup_picture(pNv, pict_src, src, 0, &sc, &sa))
return FALSE;
-
- /* Set mask format */
- if (mask && !setup_texture(pNv, 1, pict_mask, mask))
+ if (!setup_picture(pNv, pict_mask, mask, 1, &mc, &ma))
return FALSE;
- /* Set the register combiners up. */
- setup_combiners(pNv, pict_src, pict_mask, op);
-
- /* Set PictOp */
- setup_blend_function(pNv, pict_dst, op);
+ /* configure register combiners */
+ BEGIN_NV04(push, NV10_3D(RC_IN_ALPHA(0)), 1);
+ PUSH_DATA (push, sa | ma);
+ BEGIN_NV04(push, NV10_3D(RC_IN_RGB(0)), 1);
+ if (effective_component_alpha(pict_mask)) {
+ if (needs_src_alpha(op))
+ PUSH_DATA(push, sa | mc);
+ else
+ PUSH_DATA(push, sc | mc);
+ } else {
+ PUSH_DATA(push, sc | ma);
+ }
nouveau_pushbuf_bufctx(push, pNv->bufctx);
if (nouveau_pushbuf_validate(push)) {