/*
* Copyright 2007 Stephane Marchesin
* Copyright 2007 Arthur Huillet
* Copyright 2007 Peter Winters
* Copyright 2009 Francisco Jerez
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "nv_include.h"
#include "nv04_pushbuf.h"
/* Texture/Render target formats. */
static struct pict_format {
int exa;
int hw;
} nv10_tex_format_pot[] = {
{ PICT_a8, 0x80 },
{ PICT_r5g6b5, 0x280 },
{ PICT_x8r8g8b8, 0x300 },
{ PICT_a8r8g8b8, 0x300 },
{},
}, nv10_tex_format_rect[] = {
{ PICT_a8, 0x980 },
{ PICT_r5g6b5, 0x880 },
{ PICT_x8r8g8b8, 0x900 },
{ PICT_a8r8g8b8, 0x900 },
{},
}, nv20_tex_format_rect[] = {
{ PICT_a8, 0xd80 },
{ PICT_r5g6b5, 0x880 },
{ PICT_x8r8g8b8, 0x900 },
{ PICT_a8r8g8b8, 0x900 },
{},
}, nv10_rt_format[] = {
{ PICT_r5g6b5, 0x103 },
{ PICT_x8r8g8b8, 0x108 },
{ PICT_a8r8g8b8, 0x108 },
{},
};
static int
get_tex_format(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.
*/
struct pict_format *format =
pict->repeat != RepeatNone ? nv10_tex_format_pot :
pNv->Architecture == NV_ARCH_20 ? nv20_tex_format_rect :
nv10_tex_format_rect;
for (; format->hw; format++) {
if (format->exa == pict->format)
return format->hw;
}
return 0;
}
static int
get_rt_format(PicturePtr pict)
{
struct pict_format *format = nv10_rt_format;
for (; format->hw; format++) {
if (format->exa == pict->format)
return format->hw;
}
return 0;
}
/* Blending functions. */
#define SF(x) NV10TCL_BLEND_FUNC_SRC_##x
#define DF(x) NV10TCL_BLEND_FUNC_DST_##x
static struct pict_op {
int src;
int dst;
} nv10_pict_op[] = {
{ SF(ZERO), DF(ZERO) }, /* Clear */
{ SF(ONE), DF(ZERO) }, /* Src */
{ SF(ZERO), DF(ONE) }, /* Dst */
{ SF(ONE), DF(ONE_MINUS_SRC_ALPHA) }, /* Over */
{ SF(ONE_MINUS_DST_ALPHA), DF(ONE) }, /* OverReverse */
{ SF(DST_ALPHA), DF(ZERO) }, /* In */
{ SF(ZERO), DF(SRC_ALPHA) }, /* InReverse */
{ SF(ONE_MINUS_DST_ALPHA), DF(ZERO) }, /* Out */
{ SF(ZERO), DF(ONE_MINUS_SRC_ALPHA) }, /* OutReverse */
{ SF(DST_ALPHA), DF(ONE_MINUS_SRC_ALPHA) }, /* Atop */
{ SF(ONE_MINUS_DST_ALPHA), DF(SRC_ALPHA) }, /* AtopReverse */
{ SF(ONE_MINUS_DST_ALPHA), DF(ONE_MINUS_SRC_ALPHA) }, /* Xor */
{ SF(ONE), DF(ONE) }, /* Add */
};
static inline Bool
needs_src_alpha(int op)
{
return nv10_pict_op[op].dst == DF(ONE_MINUS_SRC_ALPHA)
|| nv10_pict_op[op].dst == DF(SRC_ALPHA);
}
static inline Bool
needs_src(int op)
{
return nv10_pict_op[op].src != DF(ZERO);
}
static inline Bool
effective_component_alpha(PicturePtr mask)
{
return mask && mask->componentAlpha && PICT_FORMAT_RGB(mask->format);
}
static Bool
check_texture(PicturePtr pict)
{
int w, h;
if (!pict->pDrawable)
NOUVEAU_FALLBACK("Solid and gradient pictures unsupported\n");
w = pict->pDrawable->width;
h = pict->pDrawable->height;
if (w > 2046 || h > 2046)
NOUVEAU_FALLBACK("picture too large, %dx%d\n", w, h);
if (!get_tex_format(pict))
return FALSE;
if (pict->filter != PictFilterNearest &&
pict->filter != PictFilterBilinear)
return FALSE;
/* We cannot repeat on NV10 because NPOT textures do not
* support this. unfortunately. */
if (pict->repeat != RepeatNone)
/* we can repeat 1x1 textures */
if (!(w == 1 && h == 1))
return FALSE;
return TRUE;
}
static Bool
check_render_target(PicturePtr pict)
{
int w = pict->pDrawable->width;
int h = pict->pDrawable->height;
if (w > 4096 || h > 4096)
return FALSE;
if (!get_rt_format(pict))
return FALSE;
return TRUE;
}
static Bool
check_pict_op(int op)
{
/* We do no saturate, disjoint, conjoint, though we
* could do e.g. DisjointClear which really is
* Clear. */
return op < PictOpSaturate;
}
#if 0
static void
print_fallback_info(char *reason, int op, PicturePtr src, PicturePtr mask,
PicturePtr dst)
{
char out2[4096];
char *out = out2;
sprintf(out, "%s ", reason);
out += strlen(out);
switch (op) {
case PictOpClear:
sprintf(out, "PictOpClear ");
break;
case PictOpSrc:
sprintf(out, "PictOpSrc ");
break;
case PictOpDst:
sprintf(out, "PictOpDst ");
break;
case PictOpOver:
sprintf(out, "PictOpOver ");
break;
case PictOpOutReverse:
sprintf(out, "PictOpOutReverse ");
break;
case PictOpAdd:
sprintf(out, "PictOpAdd ");
break;
default:
sprintf(out, "PictOp%d ", op);
}
out += strlen(out);
switch (src->format) {
case PICT_a8r8g8b8:
sprintf(out, "A8R8G8B8 ");
break;
case PICT_x8r8g8b8:
sprintf(out, "X8R8G8B8 ");
break;
case PICT_x8b8g8r8:
sprintf(out, "X8B8G8R8 ");
break;
case PICT_r5g6b5:
sprintf(out, "R5G6B5 ");
break;
case PICT_a8:
sprintf(out, "A8 ");
break;
case PICT_a1:
sprintf(out, "A1 ");
break;
default:
sprintf(out, "%x ", src->format);
}
out += strlen(out);
sprintf(out, "(%dx%d) ", src->pDrawable->width,
src->pDrawable->height);
if (src->repeat != RepeatNone)
strcat(out, "R ");
strcat(out, "-> ");
out += strlen(out);
switch (dst->format) {
case PICT_a8r8g8b8:
sprintf(out, "A8R8G8B8 ");
break;
case PICT_x8r8g8b8:
sprintf(out, "X8R8G8B8 ");
break;
case PICT_x8b8g8r8:
sprintf(out, "X8B8G8R8 ");
break;
case PICT_r5g6b5:
sprintf(out, "R5G6B5 ");
break;
case PICT_a8:
sprintf(out, "A8 ");
break;
case PICT_a1:
sprintf(out, "A1 ");
break;
default:
sprintf(out, "%x ", dst->format);
}
out += strlen(out);
sprintf(out, "(%dx%d) ", dst->pDrawable->width,
dst->pDrawable->height);
if (dst->repeat != RepeatNone)
strcat(out, "R ");
out += strlen(out);
if (!mask)
sprintf(out, "& NONE");
else {
switch (mask->format) {
case PICT_a8r8g8b8:
sprintf(out, "& A8R8G8B8 ");
break;
case PICT_x8r8g8b8:
sprintf(out, "& X8R8G8B8 ");
break;
case PICT_x8b8g8r8:
sprintf(out, "& X8B8G8R8 ");
break;
case PICT_a8:
sprintf(out, "& A8 ");
break;
case PICT_a1:
sprintf(out, "& A1 ");
break;
default:
sprintf(out, "& %x ", mask->format);
}
out += strlen(out);
sprintf(out, "(%dx%d) ", mask->pDrawable->width,
mask->pDrawable->height);
if (mask->repeat != RepeatNone)
strcat(out, "R ");
if (mask->componentAlpha)
strcat(out, "C ");
out += strlen(out);
}
strcat(out, "\n");
xf86DrvMsg(0, X_INFO, "%s", out2);
}
#else
#define print_fallback_info(...)
#endif
Bool
NV10EXACheckComposite(int op, PicturePtr src, PicturePtr mask, PicturePtr dst)
{
if (!check_pict_op(op)) {
print_fallback_info("pictop", op, src, mask, dst);
return FALSE;
}
if (!check_render_target(dst)) {
print_fallback_info("dst", op, src, mask, dst);
return FALSE;
}
if (!check_texture(src)) {
print_fallback_info("src", op, src, mask, dst);
return FALSE;
}
if (mask) {
if (!check_texture(mask)) {
print_fallback_info("mask", op, src,
mask, dst);
return FALSE;
}
if (effective_component_alpha(mask) &&
needs_src(op) && needs_src_alpha(op)) {
print_fallback_info("ca-mask", op, src,
mask, dst);
return FALSE;
}
}
print_fallback_info("Accelerating", op, src, mask, dst);
return TRUE;
}
static Bool
setup_texture(NVPtr pNv, int unit, PicturePtr pict, PixmapPtr pixmap)
{
struct nouveau_channel *chan = pNv->chan;
struct nouveau_grobj *celsius = pNv->Nv3D;
struct nouveau_bo *bo = nouveau_pixmap_bo(pixmap);
unsigned tex_reloc = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
long w = pict->pDrawable->width,
h = pict->pDrawable->height;
unsigned int txfmt =
NV10TCL_TX_FORMAT_WRAP_T_CLAMP_TO_EDGE |
NV10TCL_TX_FORMAT_WRAP_S_CLAMP_TO_EDGE |
log2i(w) << 20 | log2i(h) << 16 |
1 << 12 | /* lod == 1 */
get_tex_format(pict) |
0x50 /* UNK */;
BEGIN_RING(chan, celsius, NV10TCL_TX_OFFSET(unit), 1);
if (OUT_RELOCl(chan, bo, 0, tex_reloc))
return FALSE;
if (pict->repeat == RepeatNone) {
/* NPOT_SIZE expects an even number for width, we can
* round up uneven numbers here because EXA always
* gives 64 byte aligned pixmaps and for all formats
* we support 64 bytes represents an even number of
* pixels
*/
w = (w + 1) &~ 1;
BEGIN_RING(chan, celsius, NV10TCL_TX_NPOT_PITCH(unit), 1);
OUT_RING (chan, exaGetPixmapPitch(pixmap) << 16);
BEGIN_RING(chan, celsius, NV10TCL_TX_NPOT_SIZE(unit), 1);
OUT_RING (chan, w << 16 | h);
}
BEGIN_RING(chan, celsius, NV10TCL_TX_FORMAT(unit), 1 );
if (OUT_RELOCd(chan, bo, txfmt, tex_reloc | NOUVEAU_BO_OR,
NV10TCL_TX_FORMAT_DMA0, NV10TCL_TX_FORMAT_DMA1))
return FALSE;
BEGIN_RING(chan, celsius, NV10TCL_TX_ENABLE(unit), 1 );
OUT_RING (chan, NV10TCL_TX_ENABLE_ENABLE);
BEGIN_RING(chan, celsius, NV10TCL_TX_FILTER(unit), 1);
if (pict->filter == PictFilterNearest)
OUT_RING(chan, (NV10TCL_TX_FILTER_MAGNIFY_NEAREST |
NV10TCL_TX_FILTER_MINIFY_NEAREST));
else
OUT_RING(chan, (NV10TCL_TX_FILTER_MAGNIFY_LINEAR |
NV10TCL_TX_FILTER_MINIFY_LINEAR));
return TRUE;
}
static Bool
setup_render_target(NVPtr pNv, PicturePtr pict, PixmapPtr pixmap)
{
struct nouveau_channel *chan = pNv->chan;
struct nouveau_grobj *celsius = pNv->Nv3D;
struct nouveau_bo *bo = nouveau_pixmap_bo(pixmap);
BEGIN_RING(chan, celsius, NV10TCL_RT_FORMAT, 2);
OUT_RING (chan, get_rt_format(pict));
OUT_RING (chan, (exaGetPixmapPitch(pixmap) << 16 |
exaGetPixmapPitch(pixmap)));
BEGIN_RING(chan, celsius, NV10TCL_COLOR_OFFSET, 1);
if (OUT_RELOCl(chan, bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR))
return FALSE;
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 to a constant 1. */
#define RC_IN_ONE(input) \
(NV10TCL_RC_IN_RGB_##input##_INPUT_ZERO | \
NV10TCL_RC_IN_RGB_##input##_COMPONENT_USAGE_ALPHA | \
NV10TCL_RC_IN_RGB_##input##_MAPPING_UNSIGNED_INVERT)
/* Bind the combiner variable to the specified channel from
* the texture unit . */
#define RC_IN_TEX(input, chan, unit) \
(NV10TCL_RC_IN_RGB_##input##_INPUT_TEXTURE##unit | \
NV10TCL_RC_IN_RGB_##input##_COMPONENT_USAGE_##chan)
/* Bind the combiner variable to the specified channel from
* the constant color . */
#define RC_IN_COLOR(input, chan, unit) \
(NV10TCL_RC_IN_RGB_##input##_INPUT_CONSTANT_COLOR##unit | \
NV10TCL_RC_IN_RGB_##input##_COMPONENT_USAGE_##chan)
static void
setup_combiners(NVPtr pNv, PicturePtr src, PicturePtr mask)
{
struct nouveau_channel *chan = pNv->chan;
struct nouveau_grobj *celsius = pNv->Nv3D;
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(pNv->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_RING(chan, celsius, NV10TCL_RC_IN_ALPHA(0), 1);
OUT_RING (chan, rc_in_alpha);
BEGIN_RING(chan, celsius, NV10TCL_RC_IN_RGB(0), 1);
OUT_RING (chan, rc_in_rgb);
}
static void
setup_blend_function(NVPtr pNv)
{
struct nouveau_channel *chan = pNv->chan;
struct nouveau_grobj *celsius = pNv->Nv3D;
struct pict_op *op = &nv10_pict_op[pNv->alu];
int src_factor = op->src;
int dst_factor = op->dst;
if (src_factor == SF(ONE_MINUS_DST_ALPHA) &&
!PICT_FORMAT_A(pNv->pdpict->format))
/* ONE_MINUS_DST_ALPHA doesn't always do the right thing for
* framebuffers without alpha channel. But it's the same as
* ZERO in that case.
*/
src_factor = SF(ZERO);
if (effective_component_alpha(pNv->pmpict)) {
if (dst_factor == DF(SRC_ALPHA))
dst_factor = DF(SRC_COLOR);
else if (dst_factor == DF(ONE_MINUS_SRC_ALPHA))
dst_factor = DF(ONE_MINUS_SRC_COLOR);
}
BEGIN_RING(chan, celsius, NV10TCL_BLEND_FUNC_SRC, 2);
OUT_RING (chan, src_factor);
OUT_RING (chan, dst_factor);
BEGIN_RING(chan, celsius, NV10TCL_BLEND_FUNC_ENABLE, 1);
OUT_RING (chan, 1);
}
static void
NV10StateCompositeReemit(struct nouveau_channel *chan)
{
ScrnInfoPtr pScrn = chan->user_private;
NVPtr pNv = NVPTR(pScrn);
NV10EXAPrepareComposite(pNv->alu, pNv->pspict, pNv->pmpict, pNv->pdpict,
pNv->pspix, pNv->pmpix, pNv->pdpix);
}
Bool
NV10EXAPrepareComposite(int op,
PicturePtr pict_src,
PicturePtr pict_mask,
PicturePtr pict_dst,
PixmapPtr src,
PixmapPtr mask,
PixmapPtr dst)
{
ScrnInfoPtr pScrn = xf86Screens[dst->drawable.pScreen->myNum];
NVPtr pNv = NVPTR(pScrn);
struct nouveau_channel *chan = pNv->chan;
if (MARK_RING(chan, 128, 5))
return FALSE;
pNv->alu = op;
pNv->pspict = pict_src;
pNv->pmpict = pict_mask;
pNv->pdpict = pict_dst;
pNv->pspix = src;
pNv->pmpix = mask;
pNv->pdpix = dst;
/* Set dst format */
if (!setup_render_target(pNv, pict_dst, dst))
goto fail;
/* Set src format */
if (!setup_texture(pNv, 0, pict_src, src))
goto fail;
/* Set mask format */
if (mask &&
!setup_texture(pNv, 1, pict_mask, mask))
goto fail;
/* Set the register combiners up. */
setup_combiners(pNv, pict_src, pict_mask);
/* Set PictOp */
setup_blend_function(pNv);
chan->flush_notify = NV10StateCompositeReemit;
return TRUE;
fail:
MARK_UNDO(chan);
return FALSE;
}
#define QUAD(x, y, w, h) \
{{{ IntToxFixed(x), IntToxFixed(y), xFixed1 }}, \
{{ IntToxFixed(x + w), IntToxFixed(y), xFixed1 }}, \
{{ IntToxFixed(x + w), IntToxFixed(y + h), xFixed1 }}, \
{{ IntToxFixed(x), IntToxFixed(y + h), xFixed1 }}}
#define MAP(f, p, v, ...) do { \
int __i; \
for (__i = 0; __i < sizeof(v)/sizeof((v)[0]); __i++) \
f(p, __i, v, ## __VA_ARGS__); \
} while (0);
#define xFixedToFloat(v) \
((float)xFixedToInt((v)) + ((float)xFixedFrac(v) / 65536.0))
#define OUT_RINGi(chan, v, i) \
OUT_RINGf(chan, xFixedToFloat((v).vector[i]))
static inline void
emit_vertex(NVPtr pNv, int i, PictVector pos[],
PictVector tex0[], PictVector tex1[])
{
struct nouveau_channel *chan = pNv->chan;
struct nouveau_grobj *celsius = pNv->Nv3D;
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_TX0_2F_S, 2);
OUT_RINGi (chan, tex0[i], 0);
OUT_RINGi (chan, tex0[i], 1);
if (tex1) {
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_TX1_2F_S, 2);
OUT_RINGi (chan, tex1[i], 0);
OUT_RINGi (chan, tex1[i], 1);
}
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_POS_3F_X, 3);
OUT_RINGi (chan, pos[i], 0);
OUT_RINGi (chan, pos[i], 1);
OUT_RINGf (chan, 0);
}
static inline void
transform_vertex(PictTransformPtr t, int i, PictVector vs[])
{
if (t)
PictureTransformPoint(t, &vs[i]);
}
void
NV10EXAComposite(PixmapPtr pix_dst,
int srcX, int srcY,
int maskX, int maskY,
int dstX, int dstY,
int width, int height)
{
ScrnInfoPtr pScrn = xf86Screens[pix_dst->drawable.pScreen->myNum];
NVPtr pNv = NVPTR(pScrn);
struct nouveau_channel *chan = pNv->chan;
struct nouveau_grobj *celsius = pNv->Nv3D;
PicturePtr mask = pNv->pmpict,
src = pNv->pspict;
PictVector dstq[4] = QUAD(dstX, dstY, width, height),
maskq[4] = QUAD(maskX, maskY, width, height),
srcq[4] = QUAD(srcX, srcY, width, height);
MAP(transform_vertex, src->transform, srcq);
if (mask)
MAP(transform_vertex, mask->transform, maskq);
WAIT_RING (chan, 64);
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_BEGIN_END, 1);
OUT_RING (chan, NV10TCL_VERTEX_BEGIN_END_QUADS);
MAP(emit_vertex, pNv, dstq, srcq, mask ? maskq : NULL);
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_BEGIN_END, 1);
OUT_RING (chan, NV10TCL_VERTEX_BEGIN_END_STOP);
}
void
NV10EXADoneComposite(PixmapPtr dst)
{
ScrnInfoPtr pScrn = xf86Screens[dst->drawable.pScreen->myNum];
NVPtr pNv = NVPTR(pScrn);
struct nouveau_channel *chan = pNv->chan;
chan->flush_notify = NULL;
}
Bool
NVAccelInitNV10TCL(ScrnInfoPtr pScrn)
{
NVPtr pNv = NVPTR(pScrn);
struct nouveau_channel *chan = pNv->chan;
struct nouveau_grobj *celsius;
uint32_t class = 0;
int i;
if (((pNv->dev->chipset & 0xf0) != NV_ARCH_10) &&
((pNv->dev->chipset & 0xf0) != NV_ARCH_20))
return FALSE;
if (pNv->dev->chipset >= 0x20 || pNv->dev->chipset == 0x1a)
class = NV11TCL;
else if (pNv->dev->chipset >= 0x17)
class = NV17TCL;
else if (pNv->dev->chipset >= 0x11)
class = NV11TCL;
else
class = NV10TCL;
if (!pNv->Nv3D) {
if (nouveau_grobj_alloc(pNv->chan, Nv3D, class, &pNv->Nv3D))
return FALSE;
}
celsius = pNv->Nv3D;
BEGIN_RING(chan, celsius, NV10TCL_DMA_NOTIFY, 1);
OUT_RING (chan, chan->nullobj->handle);
BEGIN_RING(chan, celsius, NV10TCL_DMA_IN_MEMORY0, 2);
OUT_RING (chan, pNv->chan->vram->handle);
OUT_RING (chan, pNv->chan->gart->handle);
BEGIN_RING(chan, celsius, NV10TCL_DMA_IN_MEMORY2, 2);
OUT_RING (chan, pNv->chan->vram->handle);
OUT_RING (chan, pNv->chan->vram->handle);
BEGIN_RING(chan, celsius, NV10TCL_NOP, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_RT_HORIZ, 2);
OUT_RING (chan, 2048 << 16 | 0);
OUT_RING (chan, 2048 << 16 | 0);
BEGIN_RING(chan, celsius, NV10TCL_ZETA_OFFSET, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_VIEWPORT_CLIP_MODE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_VIEWPORT_CLIP_HORIZ(0), 1);
OUT_RING (chan, 0x7ff << 16 | 0x800800);
BEGIN_RING(chan, celsius, NV10TCL_VIEWPORT_CLIP_VERT(0), 1);
OUT_RING (chan, 0x7ff << 16 | 0x800800);
for (i = 1; i < 8; i++) {
BEGIN_RING(chan, celsius, NV10TCL_VIEWPORT_CLIP_HORIZ(i), 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_VIEWPORT_CLIP_VERT(i), 1);
OUT_RING (chan, 0);
}
BEGIN_RING(chan, celsius, 0x290, 1);
OUT_RING (chan, (0x10<<16)|1);
BEGIN_RING(chan, celsius, 0x3f4, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_NOP, 1);
OUT_RING (chan, 0);
if (class != NV10TCL) {
/* For nv11, nv17 */
BEGIN_RING(chan, celsius, 0x120, 3);
OUT_RING (chan, 0);
OUT_RING (chan, 1);
OUT_RING (chan, 2);
BEGIN_RING(chan, pNv->NvImageBlit, 0x120, 3);
OUT_RING (chan, 0);
OUT_RING (chan, 1);
OUT_RING (chan, 2);
BEGIN_RING(chan, celsius, NV10TCL_NOP, 1);
OUT_RING (chan, 0);
}
BEGIN_RING(chan, celsius, NV10TCL_NOP, 1);
OUT_RING (chan, 0);
/* Set state */
BEGIN_RING(chan, celsius, NV10TCL_FOG_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_ALPHA_FUNC_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_ALPHA_FUNC_FUNC, 2);
OUT_RING (chan, 0x207);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_TX_ENABLE(0), 2);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_RC_IN_ALPHA(0), 6);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_RC_OUT_ALPHA(0), 6);
OUT_RING (chan, 0x00000c00);
OUT_RING (chan, 0);
OUT_RING (chan, 0x00000c00);
OUT_RING (chan, 0x18000000);
OUT_RING (chan, 0x300c0000);
OUT_RING (chan, 0x00001c80);
BEGIN_RING(chan, celsius, NV10TCL_BLEND_FUNC_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_DITHER_ENABLE, 2);
OUT_RING (chan, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_LINE_SMOOTH_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_WEIGHT_ENABLE, 2);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_BLEND_FUNC_SRC, 4);
OUT_RING (chan, 1);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, 0x8006);
BEGIN_RING(chan, celsius, NV10TCL_STENCIL_MASK, 8);
OUT_RING (chan, 0xff);
OUT_RING (chan, 0x207);
OUT_RING (chan, 0);
OUT_RING (chan, 0xff);
OUT_RING (chan, 0x1e00);
OUT_RING (chan, 0x1e00);
OUT_RING (chan, 0x1e00);
OUT_RING (chan, 0x1d01);
BEGIN_RING(chan, celsius, NV10TCL_NORMALIZE_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_FOG_ENABLE, 2);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_LIGHT_MODEL, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_SEPARATE_SPECULAR_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_ENABLED_LIGHTS, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_POLYGON_OFFSET_POINT_ENABLE, 3);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_DEPTH_FUNC, 1);
OUT_RING (chan, 0x201);
BEGIN_RING(chan, celsius, NV10TCL_DEPTH_WRITE_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_DEPTH_TEST_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_POLYGON_OFFSET_FACTOR, 2);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_POINT_SIZE, 1);
OUT_RING (chan, 8);
BEGIN_RING(chan, celsius, NV10TCL_POINT_PARAMETERS_ENABLE, 2);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_LINE_WIDTH, 1);
OUT_RING (chan, 8);
BEGIN_RING(chan, celsius, NV10TCL_LINE_SMOOTH_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_POLYGON_MODE_FRONT, 2);
OUT_RING (chan, 0x1b02);
OUT_RING (chan, 0x1b02);
BEGIN_RING(chan, celsius, NV10TCL_CULL_FACE, 2);
OUT_RING (chan, 0x405);
OUT_RING (chan, 0x901);
BEGIN_RING(chan, celsius, NV10TCL_POLYGON_SMOOTH_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_CULL_FACE_ENABLE, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_TX_GEN_MODE_S(0), 8);
for (i = 0; i < 8; i++)
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_FOG_EQUATION_CONSTANT, 3);
OUT_RING (chan, 0x3fc00000); /* -1.50 */
OUT_RING (chan, 0xbdb8aa0a); /* -0.09 */
OUT_RING (chan, 0); /* 0.00 */
BEGIN_RING(chan, celsius, NV10TCL_NOP, 1);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_FOG_MODE, 2);
OUT_RING (chan, 0x802);
OUT_RING (chan, 2);
/* for some reason VIEW_MATRIX_ENABLE need to be 6 instead of 4 when
* using texturing, except when using the texture matrix
*/
BEGIN_RING(chan, celsius, NV10TCL_VIEW_MATRIX_ENABLE, 1);
OUT_RING (chan, 6);
BEGIN_RING(chan, celsius, NV10TCL_COLOR_MASK, 1);
OUT_RING (chan, 0x01010101);
BEGIN_RING(chan, celsius, NV10TCL_PROJECTION_MATRIX(0), 16);
for(i = 0; i < 16; i++)
OUT_RINGf(chan, i/4 == i%4 ? 1.0 : 0.0);
BEGIN_RING(chan, celsius, NV10TCL_DEPTH_RANGE_NEAR, 2);
OUT_RING (chan, 0);
OUT_RINGf (chan, 65536.0);
BEGIN_RING(chan, celsius, NV10TCL_VIEWPORT_TRANSLATE_X, 4);
OUT_RINGf (chan, -2048.0);
OUT_RINGf (chan, -2048.0);
OUT_RINGf (chan, 0);
OUT_RING (chan, 0);
/* Set vertex component */
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_COL_4F_R, 4);
OUT_RINGf (chan, 1.0);
OUT_RINGf (chan, 1.0);
OUT_RINGf (chan, 1.0);
OUT_RINGf (chan, 1.0);
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_COL2_3F_R, 3);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_NOR_3F_X, 3);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RINGf (chan, 1.0);
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_TX0_4F_S, 4);
OUT_RINGf (chan, 0.0);
OUT_RINGf (chan, 0.0);
OUT_RINGf (chan, 0.0);
OUT_RINGf (chan, 1.0);
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_TX1_4F_S, 4);
OUT_RINGf (chan, 0.0);
OUT_RINGf (chan, 0.0);
OUT_RINGf (chan, 0.0);
OUT_RINGf (chan, 1.0);
BEGIN_RING(chan, celsius, NV10TCL_VERTEX_FOG_1F, 1);
OUT_RINGf (chan, 0.0);
BEGIN_RING(chan, celsius, NV10TCL_EDGEFLAG_ENABLE, 1);
OUT_RING (chan, 1);
return TRUE;
}