static boolean
nv30_state_stipple_validate(struct nv30_context *nv30)
{
	struct pipe_rasterizer_state *rast = &nv30->rasterizer->pipe;
	struct nouveau_grobj *rankine = nv30->screen->rankine;
	struct nouveau_stateobj *so;

	if (nv30->state.hw[NV30_STATE_STIPPLE] &&
	   (rast->poly_stipple_enable == 0 && nv30->state.stipple_enabled == 0))
		return FALSE;

	if (rast->poly_stipple_enable) {
		unsigned i;

		so = so_new(35, 0);
		so_method(so, rankine, NV34TCL_POLYGON_STIPPLE_ENABLE, 1);
		so_data  (so, 1);
		so_method(so, rankine, NV34TCL_POLYGON_STIPPLE_PATTERN(0), 32);
		for (i = 0; i < 32; i++)
			so_data(so, nv30->stipple[i]);
	} else {
		so = so_new(2, 0);
		so_method(so, rankine, NV34TCL_POLYGON_STIPPLE_ENABLE, 1);
		so_data  (so, 0);
	}

	so_ref(so, &nv30->state.hw[NV30_STATE_STIPPLE]);
	so_ref(NULL, &so);
	return TRUE;
}
static boolean
nv30_state_scissor_validate(struct nv30_context *nv30)
{
	struct pipe_rasterizer_state *rast = &nv30->rasterizer->pipe;
	struct pipe_scissor_state *s = &nv30->scissor;
	struct nouveau_stateobj *so;

	if (nv30->state.hw[NV30_STATE_SCISSOR] &&
	    (rast->scissor == 0 && nv30->state.scissor_enabled == 0))
		return FALSE;
	nv30->state.scissor_enabled = rast->scissor;

	so = so_new(3, 0);
	so_method(so, nv30->screen->rankine, NV34TCL_SCISSOR_HORIZ, 2);
	if (nv30->state.scissor_enabled) {
		so_data  (so, ((s->maxx - s->minx) << 16) | s->minx);
		so_data  (so, ((s->maxy - s->miny) << 16) | s->miny);
	} else {
		so_data  (so, 4096 << 16);
		so_data  (so, 4096 << 16);
	}

	so_ref(so, &nv30->state.hw[NV30_STATE_SCISSOR]);
	so_ref(NULL, &so);
	return TRUE;
}
Beispiel #3
0
static boolean
nv40_vbo_static_attrib(struct nv40_context *nv40, struct nouveau_stateobj *so,
		       int attrib, struct pipe_vertex_element *ve,
		       struct pipe_vertex_buffer *vb)
{
	struct pipe_winsys *ws = nv40->pipe.winsys;
	struct nouveau_grobj *curie = nv40->screen->curie;
	unsigned type, ncomp;
	void *map;

	if (nv40_vbo_format_to_hw(ve->src_format, &type, &ncomp))
		return FALSE;

	map  = ws->buffer_map(ws, vb->buffer, PIPE_BUFFER_USAGE_CPU_READ);
	map += vb->buffer_offset + ve->src_offset;

	switch (type) {
	case NV40TCL_VTXFMT_TYPE_FLOAT:
	{
		float *v = map;

		switch (ncomp) {
		case 4:
			so_method(so, curie, NV40TCL_VTX_ATTR_4F_X(attrib), 4);
			so_data  (so, fui(v[0]));
			so_data  (so, fui(v[1]));
			so_data  (so, fui(v[2]));
			so_data  (so, fui(v[3]));
			break;
		case 3:
			so_method(so, curie, NV40TCL_VTX_ATTR_3F_X(attrib), 3);
			so_data  (so, fui(v[0]));
			so_data  (so, fui(v[1]));
			so_data  (so, fui(v[2]));
			break;
		case 2:
			so_method(so, curie, NV40TCL_VTX_ATTR_2F_X(attrib), 2);
			so_data  (so, fui(v[0]));
			so_data  (so, fui(v[1]));
			break;
		case 1:
			so_method(so, curie, NV40TCL_VTX_ATTR_1F(attrib), 1);
			so_data  (so, fui(v[0]));
			break;
		default:
			ws->buffer_unmap(ws, vb->buffer);
			return FALSE;
		}
	}
		break;
	default:
		ws->buffer_unmap(ws, vb->buffer);
		return FALSE;
	}

	ws->buffer_unmap(ws, vb->buffer);

	return TRUE;
}
Beispiel #4
0
static int
nv50_validate_textures(struct nv50_context *nv50, struct nouveau_stateobj *so,
		       unsigned p)
{
	struct nouveau_grobj *eng2d = nv50->screen->eng2d;
	struct nouveau_grobj *tesla = nv50->screen->tesla;
	unsigned unit, j;

	const unsigned rll = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW;
	const unsigned rlh = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH
		| NOUVEAU_BO_OR;

	nv50_so_init_sifc(nv50, so, nv50->screen->tic, NOUVEAU_BO_VRAM,
			  p * (32 * 8 * 4), nv50->sampler_view_nr[p] * 8 * 4);

	for (unit = 0; unit < nv50->sampler_view_nr[p]; ++unit) {
		struct nv50_sampler_view *view =
			nv50_sampler_view(nv50->sampler_views[p][unit]);

		so_method(so, eng2d, NV50_2D_SIFC_DATA | (2 << 29), 8);
		if (view) {
			uint32_t tic2 = view->tic[2];
			struct nv50_miptree *mt =
				nv50_miptree(view->pipe.texture);

			tic2 &= ~NV50TIC_0_2_NORMALIZED_COORDS;
			if (nv50->sampler[p][unit]->normalized)
				tic2 |= NV50TIC_0_2_NORMALIZED_COORDS;
			view->tic[2] = tic2;

			so_data  (so, view->tic[0]);
			so_reloc (so, mt->base.bo, 0, rll, 0, 0);
			so_reloc (so, mt->base.bo, 0, rlh, tic2, tic2);
			so_datap (so, &view->tic[3], 5);

			/* Set TEX insn $t src binding $unit in program type p
			 * to TIC, TSC entry (32 * p + unit), mark valid (1).
			 */
			so_method(so, tesla, NV50TCL_BIND_TIC(p), 1);
			so_data  (so, ((32 * p + unit) << 9) | (unit << 1) | 1);
		} else {
			for (j = 0; j < 8; ++j)
				so_data(so, 0);
			so_method(so, tesla, NV50TCL_BIND_TIC(p), 1);
			so_data  (so, (unit << 1) | 0);
		}
	}

	for (; unit < nv50->state.sampler_view_nr[p]; unit++) {
		/* Make other bindings invalid. */
		so_method(so, tesla, NV50TCL_BIND_TIC(p), 1);
		so_data  (so, (unit << 1) | 0);
	}

	nv50->state.sampler_view_nr[p] = nv50->sampler_view_nr[p];
	return TRUE;
}
static boolean
nv30_state_viewport_validate(struct nv30_context *nv30)
{
	struct pipe_viewport_state *vpt = &nv30->viewport;
	struct nouveau_stateobj *so;

	if (nv30->state.hw[NV30_STATE_VIEWPORT] &&
	    !(nv30->dirty & NV30_NEW_VIEWPORT))
		return FALSE;

	so = so_new(3, 10, 0);
	so_method(so, nv30->screen->rankine,
		  NV34TCL_VIEWPORT_TRANSLATE_X, 8);
	so_data  (so, fui(vpt->translate[0]));
	so_data  (so, fui(vpt->translate[1]));
	so_data  (so, fui(vpt->translate[2]));
	so_data  (so, fui(vpt->translate[3]));
	so_data  (so, fui(vpt->scale[0]));
	so_data  (so, fui(vpt->scale[1]));
	so_data  (so, fui(vpt->scale[2]));
	so_data  (so, fui(vpt->scale[3]));
/*	so_method(so, nv30->screen->rankine, 0x1d78, 1);
	so_data  (so, 1);
*/
	/* TODO/FIXME: never saw value 0x0110 in renouveau dumps, only 0x0001 */
	so_method(so, nv30->screen->rankine, 0x1d78, 1);
	so_data  (so, 1);

	so_ref(so, &nv30->state.hw[NV30_STATE_VIEWPORT]);
	so_ref(NULL, &so);
	return TRUE;
}
Beispiel #6
0
void
nv50_tex_validate(struct nv50_context *nv50)
{
	struct nouveau_stateobj *so;
	struct nouveau_grobj *tesla = nv50->screen->tesla;
	unsigned p, start, push, nrlc;

	for (nrlc = 0, start = 0, push = 0, p = 0; p < PIPE_SHADER_TYPES; ++p) {
		start += MAX2(nv50->miptree_nr[p], nv50->state.miptree_nr[p]);
		push += MAX2(nv50->miptree_nr[p], nv50->state.miptree_nr[p]);
		nrlc += nv50->miptree_nr[p];
	}
	start = start * 2 + 4 * PIPE_SHADER_TYPES + 2;
	push = push * 9 + 19 * PIPE_SHADER_TYPES + 2;
	nrlc = nrlc * 2 + 2 * PIPE_SHADER_TYPES;

	so = so_new(start, push, nrlc);

	if (nv50_validate_textures(nv50, so, PIPE_SHADER_VERTEX) == FALSE ||
	    nv50_validate_textures(nv50, so, PIPE_SHADER_FRAGMENT) == FALSE) {
		so_ref(NULL, &so);

		NOUVEAU_ERR("failed tex validate\n");
		return;
	}

	so_method(so, tesla, 0x1330, 1); /* flush TIC */
	so_data  (so, 0);

	so_ref(so, &nv50->state.tic_upload);
	so_ref(NULL, &so);
}
Beispiel #7
0
struct nouveau_stateobj *
nv50_tex_validate(struct nv50_context *nv50)
{
	struct nouveau_stateobj *so;
	struct nouveau_grobj *tesla = nv50->screen->tesla;
	unsigned p, m = 0, d = 0, r = 0;

	for (p = 0; p < 3; ++p) {
		unsigned nr = MAX2(nv50->sampler_view_nr[p],
				   nv50->state.sampler_view_nr[p]);
		m += nr;
		d += nr;
		r += nv50->sampler_view_nr[p];
	}
	m = m * 2 + 3 * 4 + 1;
	d = d * 9 + 3 * 19 + 1;
	r = r * 2 + 3 * 2;

	so = so_new(m, d, r);

	if (nv50_validate_textures(nv50, so, 0) == FALSE ||
	    nv50_validate_textures(nv50, so, 2) == FALSE) {
		so_ref(NULL, &so);

		NOUVEAU_ERR("failed tex validate\n");
		return NULL;
	}

	so_method(so, tesla, 0x1330, 1); /* flush TIC */
	so_data  (so, 0);

	return so;
}
Beispiel #8
0
static void *
nv40_blend_state_create(struct pipe_context *pipe,
			const struct pipe_blend_state *cso)
{
	struct nv40_context *nv40 = nv40_context(pipe);
	struct nouveau_grobj *curie = nv40->screen->curie;
	struct nv40_blend_state *bso = CALLOC(1, sizeof(*bso));
	struct nouveau_stateobj *so = so_new(16, 0);

	if (cso->blend_enable) {
		so_method(so, curie, NV40TCL_BLEND_ENABLE, 3);
		so_data  (so, 1);
		so_data  (so, (nvgl_blend_func(cso->alpha_src_factor) << 16) |
			       nvgl_blend_func(cso->rgb_src_factor));
		so_data  (so, nvgl_blend_func(cso->alpha_dst_factor) << 16 |
			      nvgl_blend_func(cso->rgb_dst_factor));
		so_method(so, curie, NV40TCL_BLEND_EQUATION, 1);
		so_data  (so, nvgl_blend_eqn(cso->alpha_func) << 16 |
			      nvgl_blend_eqn(cso->rgb_func));
	} else {
		so_method(so, curie, NV40TCL_BLEND_ENABLE, 1);
		so_data  (so, 0);
	}

	so_method(so, curie, NV40TCL_COLOR_MASK, 1);
	so_data  (so, (((cso->colormask & PIPE_MASK_A) ? (0x01 << 24) : 0) |
		       ((cso->colormask & PIPE_MASK_R) ? (0x01 << 16) : 0) |
		       ((cso->colormask & PIPE_MASK_G) ? (0x01 <<  8) : 0) |
		       ((cso->colormask & PIPE_MASK_B) ? (0x01 <<  0) : 0)));

	if (cso->logicop_enable) {
		so_method(so, curie, NV40TCL_COLOR_LOGIC_OP_ENABLE, 2);
		so_data  (so, 1);
		so_data  (so, nvgl_logicop_func(cso->logicop_func));
	} else {
		so_method(so, curie, NV40TCL_COLOR_LOGIC_OP_ENABLE, 1);
		so_data  (so, 0);
	}

	so_method(so, curie, NV40TCL_DITHER_ENABLE, 1);
	so_data  (so, cso->dither ? 1 : 0);

	so_ref(so, &bso->so);
	so_ref(NULL, &so);
	bso->pipe = *cso;
	return (void *)bso;
}
Beispiel #9
0
static int
nv50_tex_construct(struct nv50_context *nv50, struct nouveau_stateobj *so,
		   struct nv50_miptree *mt, int unit, unsigned p)
{
	unsigned i;
	uint32_t mode;
	const struct util_format_description *desc;

	for (i = 0; i < NV50_TEX_FORMAT_LIST_SIZE; i++)
		if (nv50_tex_format_list[i].pf == mt->base.base.format)
			break;
	if (i == NV50_TEX_FORMAT_LIST_SIZE)
                return 1;

	if (nv50->sampler[p][unit]->normalized)
		mode = 0x50001000 | (1 << 31);
	else {
		mode = 0x50001000 | (7 << 14);
		assert(mt->base.base.target == PIPE_TEXTURE_2D);
	}

	mode |= ((mt->base.bo->tile_mode & 0x0f) << 22) |
		((mt->base.bo->tile_mode & 0xf0) << 21);

	desc = util_format_description(mt->base.base.format);
	assert(desc);

	if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB)
		mode |= 0x0400;

	switch (mt->base.base.target) {
	case PIPE_TEXTURE_1D:
		break;
	case PIPE_TEXTURE_2D:
		mode |= (1 << 14);
		break;
	case PIPE_TEXTURE_3D:
		mode |= (2 << 14);
		break;
	case PIPE_TEXTURE_CUBE:
		mode |= (3 << 14);
		break;
	default:
		assert(!"unsupported texture target");
		break;
	}

	so_data (so, nv50_tex_format_list[i].hw);
	so_reloc(so, mt->base.bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_LOW |
		 NOUVEAU_BO_RD, 0, 0);
	so_data (so, mode);
	so_data (so, 0x00300000);
	so_data (so, mt->base.base.width0 | (1 << 31));
	so_data (so, (mt->base.base.last_level << 28) |
		 (mt->base.base.depth0 << 16) | mt->base.base.height0);
	so_data (so, 0x03000000);
	so_data (so, mt->base.base.last_level << 4);

	return 0;
}
Beispiel #10
0
static boolean
nv50_validate_textures(struct nv50_context *nv50, struct nouveau_stateobj *so,
		       unsigned p)
{
	static const unsigned p_remap[PIPE_SHADER_TYPES] = { 0, 2, 1 };

	struct nouveau_grobj *eng2d = nv50->screen->eng2d;
	struct nouveau_grobj *tesla = nv50->screen->tesla;
	unsigned unit, j, p_hw = p_remap[p];

	nv50_so_init_sifc(nv50, so, nv50->screen->tic, NOUVEAU_BO_VRAM,
			  p * (32 * 8 * 4), nv50->miptree_nr[p] * 8 * 4);

	for (unit = 0; unit < nv50->miptree_nr[p]; ++unit) {
		struct nv50_miptree *mt = nv50->miptree[p][unit];

		so_method(so, eng2d, NV50_2D_SIFC_DATA | (2 << 29), 8);
		if (mt) {
			if (nv50_tex_construct(nv50, so, mt, unit, p))
				return FALSE;
			/* Set TEX insn $t src binding $unit in program type p
			 * to TIC, TSC entry (32 * p + unit), mark valid (1).
			 */
			so_method(so, tesla, NV50TCL_BIND_TIC(p_hw), 1);
			so_data  (so, ((32 * p + unit) << 9) | (unit << 1) | 1);
		} else {
			for (j = 0; j < 8; ++j)
				so_data(so, 0);
			so_method(so, tesla, NV50TCL_BIND_TIC(p_hw), 1);
			so_data  (so, (unit << 1) | 0);
		}
	}

	for (; unit < nv50->state.miptree_nr[p]; unit++) {
		/* Make other bindings invalid. */
		so_method(so, tesla, NV50TCL_BIND_TIC(p_hw), 1);
		so_data  (so, (unit << 1) | 0);
	}

	nv50->state.miptree_nr[p] = nv50->miptree_nr[p];
	return TRUE;
}
static boolean
nv40_state_blend_colour_validate(struct nv40_context *nv40)
{
	struct nouveau_stateobj *so = so_new(2, 0);
	struct pipe_blend_color *bcol = &nv40->blend_colour;

	so_method(so, nv40->screen->curie, NV40TCL_BLEND_COLOR, 1);
	so_data  (so, ((float_to_ubyte(bcol->color[3]) << 24) |
		       (float_to_ubyte(bcol->color[0]) << 16) |
		       (float_to_ubyte(bcol->color[1]) <<  8) |
		       (float_to_ubyte(bcol->color[2]) <<  0)));

	so_ref(so, &nv40->state.hw[NV40_STATE_BCOL]);
	so_ref(NULL, &so);
	return TRUE;
}
Beispiel #12
0
static boolean
nv40_vbo_validate(struct nv40_context *nv40)
{
	struct nouveau_stateobj *vtxbuf, *vtxfmt, *sattr = NULL;
	struct nouveau_grobj *curie = nv40->screen->curie;
	struct pipe_buffer *ib = nv40->idxbuf;
	unsigned ib_format = nv40->idxbuf_format;
	unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
	int hw;

	if (nv40->edgeflags) {
		nv40->fallback_swtnl |= NV40_NEW_ARRAYS;
		return FALSE;
	}

	vtxbuf = so_new(20, 18);
	so_method(vtxbuf, curie, NV40TCL_VTXBUF_ADDRESS(0), nv40->vtxelt_nr);
	vtxfmt = so_new(17, 0);
	so_method(vtxfmt, curie, NV40TCL_VTXFMT(0), nv40->vtxelt_nr);

	for (hw = 0; hw < nv40->vtxelt_nr; hw++) {
		struct pipe_vertex_element *ve;
		struct pipe_vertex_buffer *vb;
		unsigned type, ncomp;

		ve = &nv40->vtxelt[hw];
		vb = &nv40->vtxbuf[ve->vertex_buffer_index];

		if (!vb->stride) {
			if (!sattr)
				sattr = so_new(16 * 5, 0);

			if (nv40_vbo_static_attrib(nv40, sattr, hw, ve, vb)) {
				so_data(vtxbuf, 0);
				so_data(vtxfmt, NV40TCL_VTXFMT_TYPE_FLOAT);
				continue;
			}
		}

		if (nv40_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
			nv40->fallback_swtnl |= NV40_NEW_ARRAYS;
			so_ref(NULL, &vtxbuf);
			so_ref(NULL, &vtxfmt);
			return FALSE;
		}

		so_reloc(vtxbuf, vb->buffer, vb->buffer_offset + ve->src_offset,
			 vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
			 0, NV40TCL_VTXBUF_ADDRESS_DMA1);
		so_data (vtxfmt, ((vb->stride << NV40TCL_VTXFMT_STRIDE_SHIFT) |
				  (ncomp << NV40TCL_VTXFMT_SIZE_SHIFT) | type));
	}

	if (ib) {
		so_method(vtxbuf, curie, NV40TCL_IDXBUF_ADDRESS, 2);
		so_reloc (vtxbuf, ib, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
		so_reloc (vtxbuf, ib, ib_format, vb_flags | NOUVEAU_BO_OR,
			  0, NV40TCL_IDXBUF_FORMAT_DMA1);
	}

	so_method(vtxbuf, curie, 0x1710, 1);
	so_data  (vtxbuf, 0);

	so_ref(vtxbuf, &nv40->state.hw[NV40_STATE_VTXBUF]);
	so_ref(NULL, &vtxbuf);
	nv40->state.dirty |= (1ULL << NV40_STATE_VTXBUF);
	so_ref(vtxfmt, &nv40->state.hw[NV40_STATE_VTXFMT]);
	so_ref(NULL, &vtxfmt);
	nv40->state.dirty |= (1ULL << NV40_STATE_VTXFMT);
	so_ref(sattr, &nv40->state.hw[NV40_STATE_VTXATTR]);
	so_ref(NULL, &sattr);
	nv40->state.dirty |= (1ULL << NV40_STATE_VTXATTR);
	return FALSE;
}
Beispiel #13
0
static void *
nv50_blend_state_create(struct pipe_context *pipe,
                        const struct pipe_blend_state *cso)
{
    struct nouveau_stateobj *so = so_new(5, 24, 0);
    struct nouveau_grobj *tesla = nv50_context(pipe)->screen->tesla;
    struct nv50_blend_stateobj *bso = CALLOC_STRUCT(nv50_blend_stateobj);
    unsigned i, blend_enabled = 0;

    /*XXX ignored:
     * 	- dither
     */

    so_method(so, tesla, NV50TCL_BLEND_ENABLE(0), 8);
    if (cso->independent_blend_enable) {
        for (i = 0; i < 8; ++i) {
            so_data(so, cso->rt[i].blend_enable);
            if (cso->rt[i].blend_enable)
                blend_enabled = 1;
        }
    } else if (cso->rt[0].blend_enable) {
        blend_enabled = 1;
        for (i = 0; i < 8; i++)
            so_data(so, 1);
    } else {
        for (i = 0; i < 8; i++)
            so_data(so, 0);
    }
    if (blend_enabled) {
        so_method(so, tesla, NV50TCL_BLEND_EQUATION_RGB, 5);
        so_data  (so, nvgl_blend_eqn(cso->rt[0].rgb_func));
        so_data  (so, 0x4000 | nvgl_blend_func(cso->rt[0].rgb_src_factor));
        so_data  (so, 0x4000 | nvgl_blend_func(cso->rt[0].rgb_dst_factor));
        so_data  (so, nvgl_blend_eqn(cso->rt[0].alpha_func));
        so_data  (so, 0x4000 | nvgl_blend_func(cso->rt[0].alpha_src_factor));
        so_method(so, tesla, NV50TCL_BLEND_FUNC_DST_ALPHA, 1);
        so_data  (so, 0x4000 | nvgl_blend_func(cso->rt[0].alpha_dst_factor));
    }

    if (cso->logicop_enable == 0 ) {
        so_method(so, tesla, NV50TCL_LOGIC_OP_ENABLE, 1);
        so_data  (so, 0);
    } else {
        so_method(so, tesla, NV50TCL_LOGIC_OP_ENABLE, 2);
        so_data  (so, 1);
        so_data  (so, nvgl_logicop_func(cso->logicop_func));
    }

    so_method(so, tesla, NV50TCL_COLOR_MASK(0), 8);
    if (cso->independent_blend_enable)
        for (i = 0; i < 8; ++i)
            so_data(so, nv50_colormask(cso->rt[i].colormask));
    else {
        uint32_t cmask = nv50_colormask(cso->rt[0].colormask);
        for (i = 0; i < 8; i++)
            so_data(so, cmask);
    }

    bso->pipe = *cso;
    so_ref(so, &bso->so);
    so_ref(NULL, &so);
    return (void *)bso;
}
Beispiel #14
0
static void *
nv50_depth_stencil_alpha_state_create(struct pipe_context *pipe,
                                      const struct pipe_depth_stencil_alpha_state *cso)
{
    struct nouveau_grobj *tesla = nv50_context(pipe)->screen->tesla;
    struct nv50_zsa_stateobj *zsa = CALLOC_STRUCT(nv50_zsa_stateobj);
    struct nouveau_stateobj *so = so_new(9, 21, 0);

    so_method(so, tesla, NV50TCL_DEPTH_WRITE_ENABLE, 1);
    so_data  (so, cso->depth.writemask ? 1 : 0);
    if (cso->depth.enabled) {
        so_method(so, tesla, NV50TCL_DEPTH_TEST_ENABLE, 1);
        so_data  (so, 1);
        so_method(so, tesla, NV50TCL_DEPTH_TEST_FUNC, 1);
        so_data  (so, nvgl_comparison_op(cso->depth.func));
    } else {
        so_method(so, tesla, NV50TCL_DEPTH_TEST_ENABLE, 1);
        so_data  (so, 0);
    }

    if (cso->stencil[0].enabled) {
        so_method(so, tesla, NV50TCL_STENCIL_FRONT_ENABLE, 5);
        so_data  (so, 1);
        so_data  (so, nvgl_stencil_op(cso->stencil[0].fail_op));
        so_data  (so, nvgl_stencil_op(cso->stencil[0].zfail_op));
        so_data  (so, nvgl_stencil_op(cso->stencil[0].zpass_op));
        so_data  (so, nvgl_comparison_op(cso->stencil[0].func));
        so_method(so, tesla, NV50TCL_STENCIL_FRONT_MASK, 2);
        so_data  (so, cso->stencil[0].writemask);
        so_data  (so, cso->stencil[0].valuemask);
    } else {
        so_method(so, tesla, NV50TCL_STENCIL_FRONT_ENABLE, 1);
        so_data  (so, 0);
    }

    if (cso->stencil[1].enabled) {
        so_method(so, tesla, NV50TCL_STENCIL_BACK_ENABLE, 5);
        so_data  (so, 1);
        so_data  (so, nvgl_stencil_op(cso->stencil[1].fail_op));
        so_data  (so, nvgl_stencil_op(cso->stencil[1].zfail_op));
        so_data  (so, nvgl_stencil_op(cso->stencil[1].zpass_op));
        so_data  (so, nvgl_comparison_op(cso->stencil[1].func));
        so_method(so, tesla, NV50TCL_STENCIL_BACK_MASK, 2);
        so_data  (so, cso->stencil[1].writemask);
        so_data  (so, cso->stencil[1].valuemask);
    } else {
        so_method(so, tesla, NV50TCL_STENCIL_BACK_ENABLE, 1);
        so_data  (so, 0);
    }

    if (cso->alpha.enabled) {
        so_method(so, tesla, NV50TCL_ALPHA_TEST_ENABLE, 1);
        so_data  (so, 1);
        so_method(so, tesla, NV50TCL_ALPHA_TEST_REF, 2);
        so_data  (so, fui(cso->alpha.ref_value));
        so_data  (so, nvgl_comparison_op(cso->alpha.func));
    } else {
        so_method(so, tesla, NV50TCL_ALPHA_TEST_ENABLE, 1);
        so_data  (so, 0);
    }

    zsa->pipe = *cso;
    so_ref(so, &zsa->so);
    so_ref(NULL, &so);
    return (void *)zsa;
}
Beispiel #15
0
static void *
nv50_rasterizer_state_create(struct pipe_context *pipe,
                             const struct pipe_rasterizer_state *cso)
{
    struct nouveau_stateobj *so = so_new(15, 21, 0);
    struct nouveau_grobj *tesla = nv50_context(pipe)->screen->tesla;
    struct nv50_rasterizer_stateobj *rso =
        CALLOC_STRUCT(nv50_rasterizer_stateobj);

    /*XXX: ignored
     * 	- light_twosize
     * 	- point_smooth
     * 	- multisample
     * 	- point_sprite / sprite_coord_mode
     */

    so_method(so, tesla, NV50TCL_SHADE_MODEL, 1);
    so_data  (so, cso->flatshade ? NV50TCL_SHADE_MODEL_FLAT :
              NV50TCL_SHADE_MODEL_SMOOTH);
    so_method(so, tesla, NV50TCL_PROVOKING_VERTEX_LAST, 1);
    so_data  (so, cso->flatshade_first ? 0 : 1);

    so_method(so, tesla, NV50TCL_VERTEX_TWO_SIDE_ENABLE, 1);
    so_data  (so, cso->light_twoside);

    so_method(so, tesla, NV50TCL_LINE_WIDTH, 1);
    so_data  (so, fui(cso->line_width));
    so_method(so, tesla, NV50TCL_LINE_SMOOTH_ENABLE, 1);
    so_data  (so, cso->line_smooth ? 1 : 0);
    if (cso->line_stipple_enable) {
        so_method(so, tesla, NV50TCL_LINE_STIPPLE_ENABLE, 1);
        so_data  (so, 1);
        so_method(so, tesla, NV50TCL_LINE_STIPPLE_PATTERN, 1);
        so_data  (so, (cso->line_stipple_pattern << 8) |
                  cso->line_stipple_factor);
    } else {
        so_method(so, tesla, NV50TCL_LINE_STIPPLE_ENABLE, 1);
        so_data  (so, 0);
    }

    so_method(so, tesla, NV50TCL_POINT_SIZE, 1);
    so_data  (so, fui(cso->point_size));

    so_method(so, tesla, NV50TCL_POINT_SPRITE_ENABLE, 1);
    so_data  (so, cso->point_quad_rasterization ? 1 : 0);

    so_method(so, tesla, NV50TCL_POLYGON_MODE_FRONT, 3);
    if (cso->front_winding == PIPE_WINDING_CCW) {
        so_data(so, nvgl_polygon_mode(cso->fill_ccw));
        so_data(so, nvgl_polygon_mode(cso->fill_cw));
    } else {
        so_data(so, nvgl_polygon_mode(cso->fill_cw));
        so_data(so, nvgl_polygon_mode(cso->fill_ccw));
    }
    so_data(so, cso->poly_smooth ? 1 : 0);

    so_method(so, tesla, NV50TCL_CULL_FACE_ENABLE, 3);
    so_data  (so, cso->cull_mode != PIPE_WINDING_NONE);
    if (cso->front_winding == PIPE_WINDING_CCW) {
        so_data(so, NV50TCL_FRONT_FACE_CCW);
        switch (cso->cull_mode) {
        case PIPE_WINDING_CCW:
            so_data(so, NV50TCL_CULL_FACE_FRONT);
            break;
        case PIPE_WINDING_CW:
            so_data(so, NV50TCL_CULL_FACE_BACK);
            break;
        case PIPE_WINDING_BOTH:
            so_data(so, NV50TCL_CULL_FACE_FRONT_AND_BACK);
            break;
        default:
            so_data(so, NV50TCL_CULL_FACE_BACK);
            break;
        }
    } else {
        so_data(so, NV50TCL_FRONT_FACE_CW);
        switch (cso->cull_mode) {
        case PIPE_WINDING_CCW:
            so_data(so, NV50TCL_CULL_FACE_BACK);
            break;
        case PIPE_WINDING_CW:
            so_data(so, NV50TCL_CULL_FACE_FRONT);
            break;
        case PIPE_WINDING_BOTH:
            so_data(so, NV50TCL_CULL_FACE_FRONT_AND_BACK);
            break;
        default:
            so_data(so, NV50TCL_CULL_FACE_BACK);
            break;
        }
    }

    so_method(so, tesla, NV50TCL_POLYGON_STIPPLE_ENABLE, 1);
    so_data  (so, cso->poly_stipple_enable ? 1 : 0);

    so_method(so, tesla, NV50TCL_POLYGON_OFFSET_POINT_ENABLE, 3);
    if ((cso->offset_cw && cso->fill_cw == PIPE_POLYGON_MODE_POINT) ||
            (cso->offset_ccw && cso->fill_ccw == PIPE_POLYGON_MODE_POINT))
        so_data(so, 1);
    else
        so_data(so, 0);
    if ((cso->offset_cw && cso->fill_cw == PIPE_POLYGON_MODE_LINE) ||
            (cso->offset_ccw && cso->fill_ccw == PIPE_POLYGON_MODE_LINE))
        so_data(so, 1);
    else
        so_data(so, 0);
    if ((cso->offset_cw && cso->fill_cw == PIPE_POLYGON_MODE_FILL) ||
            (cso->offset_ccw && cso->fill_ccw == PIPE_POLYGON_MODE_FILL))
        so_data(so, 1);
    else
        so_data(so, 0);

    if (cso->offset_cw || cso->offset_ccw) {
        so_method(so, tesla, NV50TCL_POLYGON_OFFSET_FACTOR, 1);
        so_data  (so, fui(cso->offset_scale));
        so_method(so, tesla, NV50TCL_POLYGON_OFFSET_UNITS, 1);
        so_data  (so, fui(cso->offset_units * 2.0f));
    }

    rso->pipe = *cso;
    so_ref(so, &rso->so);
    so_ref(NULL, &so);
    return (void *)rso;
}
Beispiel #16
0
static void *
nv50_depth_stencil_alpha_state_create(struct pipe_context *pipe,
			const struct pipe_depth_stencil_alpha_state *cso)
{
	struct nouveau_grobj *tesla = nv50_context(pipe)->screen->tesla;
	struct nv50_zsa_stateobj *zsa = CALLOC_STRUCT(nv50_zsa_stateobj);
	struct nouveau_stateobj *so = so_new(64, 0);

	so_method(so, tesla, NV50TCL_DEPTH_WRITE_ENABLE, 1);
	so_data  (so, cso->depth.writemask ? 1 : 0);
	if (cso->depth.enabled) {
		so_method(so, tesla, NV50TCL_DEPTH_TEST_ENABLE, 1);
		so_data  (so, 1);
		so_method(so, tesla, NV50TCL_DEPTH_TEST_FUNC, 1);
		so_data  (so, nvgl_comparison_op(cso->depth.func));
	} else {
		so_method(so, tesla, NV50TCL_DEPTH_TEST_ENABLE, 1);
		so_data  (so, 0);
	}

	/* XXX: keep hex values until header is updated (names reversed) */
	if (cso->stencil[0].enabled) {
		so_method(so, tesla, 0x1380, 8);
		so_data  (so, 1);
		so_data  (so, nvgl_stencil_op(cso->stencil[0].fail_op));
		so_data  (so, nvgl_stencil_op(cso->stencil[0].zfail_op));
		so_data  (so, nvgl_stencil_op(cso->stencil[0].zpass_op));
		so_data  (so, nvgl_comparison_op(cso->stencil[0].func));
		so_data  (so, cso->stencil[0].ref_value);
		so_data  (so, cso->stencil[0].writemask);
		so_data  (so, cso->stencil[0].valuemask);
	} else {
		so_method(so, tesla, 0x1380, 1);
		so_data  (so, 0);
	}

	if (cso->stencil[1].enabled) {
		so_method(so, tesla, 0x1594, 5);
		so_data  (so, 1);
		so_data  (so, nvgl_stencil_op(cso->stencil[1].fail_op));
		so_data  (so, nvgl_stencil_op(cso->stencil[1].zfail_op));
		so_data  (so, nvgl_stencil_op(cso->stencil[1].zpass_op));
		so_data  (so, nvgl_comparison_op(cso->stencil[1].func));
		so_method(so, tesla, 0x0f54, 3);
		so_data  (so, cso->stencil[1].ref_value);
		so_data  (so, cso->stencil[1].writemask);
		so_data  (so, cso->stencil[1].valuemask);
	} else {
		so_method(so, tesla, 0x1594, 1);
		so_data  (so, 0);
	}

	if (cso->alpha.enabled) {
		so_method(so, tesla, NV50TCL_ALPHA_TEST_ENABLE, 1);
		so_data  (so, 1);
		so_method(so, tesla, NV50TCL_ALPHA_TEST_REF, 2);
		so_data  (so, fui(cso->alpha.ref_value));
		so_data  (so, nvgl_comparison_op(cso->alpha.func));
	} else {
		so_method(so, tesla, NV50TCL_ALPHA_TEST_ENABLE, 1);
		so_data  (so, 0);
	}

	zsa->pipe = *cso;
	so_ref(so, &zsa->so);
	so_ref(NULL, &so);
	return (void *)zsa;
}
Beispiel #17
0
static void *
nv40_rasterizer_state_create(struct pipe_context *pipe,
			     const struct pipe_rasterizer_state *cso)
{
	struct nv40_context *nv40 = nv40_context(pipe);
	struct nv40_rasterizer_state *rsso = CALLOC(1, sizeof(*rsso));
	struct nouveau_stateobj *so = so_new(32, 0);
	struct nouveau_grobj *curie = nv40->screen->curie;

	/*XXX: ignored:
	 * 	light_twoside
	 * 	point_smooth -nohw
	 * 	multisample
	 */

	so_method(so, curie, NV40TCL_SHADE_MODEL, 1);
	so_data  (so, cso->flatshade ? NV40TCL_SHADE_MODEL_FLAT :
				       NV40TCL_SHADE_MODEL_SMOOTH);

	so_method(so, curie, NV40TCL_LINE_WIDTH, 2);
	so_data  (so, (unsigned char)(cso->line_width * 8.0) & 0xff);
	so_data  (so, cso->line_smooth ? 1 : 0);
	so_method(so, curie, NV40TCL_LINE_STIPPLE_ENABLE, 2);
	so_data  (so, cso->line_stipple_enable ? 1 : 0);
	so_data  (so, (cso->line_stipple_pattern << 16) |
		       cso->line_stipple_factor);

	so_method(so, curie, NV40TCL_POINT_SIZE, 1);
	so_data  (so, fui(cso->point_size));

	so_method(so, curie, NV40TCL_POLYGON_MODE_FRONT, 6);
	if (cso->front_winding == PIPE_WINDING_CCW) {
		so_data(so, nvgl_polygon_mode(cso->fill_ccw));
		so_data(so, nvgl_polygon_mode(cso->fill_cw));
		switch (cso->cull_mode) {
		case PIPE_WINDING_CCW:
			so_data(so, NV40TCL_CULL_FACE_FRONT);
			break;
		case PIPE_WINDING_CW:
			so_data(so, NV40TCL_CULL_FACE_BACK);
			break;
		case PIPE_WINDING_BOTH:
			so_data(so, NV40TCL_CULL_FACE_FRONT_AND_BACK);
			break;
		default:
			so_data(so, NV40TCL_CULL_FACE_BACK);
			break;
		}
		so_data(so, NV40TCL_FRONT_FACE_CCW);
	} else {
		so_data(so, nvgl_polygon_mode(cso->fill_cw));
		so_data(so, nvgl_polygon_mode(cso->fill_ccw));
		switch (cso->cull_mode) {
		case PIPE_WINDING_CCW:
			so_data(so, NV40TCL_CULL_FACE_BACK);
			break;
		case PIPE_WINDING_CW:
			so_data(so, NV40TCL_CULL_FACE_FRONT);
			break;
		case PIPE_WINDING_BOTH:
			so_data(so, NV40TCL_CULL_FACE_FRONT_AND_BACK);
			break;
		default:
			so_data(so, NV40TCL_CULL_FACE_BACK);
			break;
		}
		so_data(so, NV40TCL_FRONT_FACE_CW);
	}
	so_data(so, cso->poly_smooth ? 1 : 0);
	so_data(so, (cso->cull_mode != PIPE_WINDING_NONE) ? 1 : 0);

	so_method(so, curie, NV40TCL_POLYGON_STIPPLE_ENABLE, 1);
	so_data  (so, cso->poly_stipple_enable ? 1 : 0);

	so_method(so, curie, NV40TCL_POLYGON_OFFSET_POINT_ENABLE, 3);
	if ((cso->offset_cw && cso->fill_cw == PIPE_POLYGON_MODE_POINT) ||
	    (cso->offset_ccw && cso->fill_ccw == PIPE_POLYGON_MODE_POINT))
		so_data(so, 1);
	else
		so_data(so, 0);
	if ((cso->offset_cw && cso->fill_cw == PIPE_POLYGON_MODE_LINE) ||
	    (cso->offset_ccw && cso->fill_ccw == PIPE_POLYGON_MODE_LINE))
		so_data(so, 1);
	else
		so_data(so, 0);
	if ((cso->offset_cw && cso->fill_cw == PIPE_POLYGON_MODE_FILL) ||
	    (cso->offset_ccw && cso->fill_ccw == PIPE_POLYGON_MODE_FILL))
		so_data(so, 1);
	else
		so_data(so, 0);
	if (cso->offset_cw || cso->offset_ccw) {
		so_method(so, curie, NV40TCL_POLYGON_OFFSET_FACTOR, 2);
		so_data  (so, fui(cso->offset_scale));
		so_data  (so, fui(cso->offset_units * 2));
	}

	so_method(so, curie, NV40TCL_POINT_SPRITE, 1);
	if (cso->point_sprite) {
		unsigned psctl = (1 << 0), i;

		for (i = 0; i < 8; i++) {
			if (cso->sprite_coord_mode[i] != PIPE_SPRITE_COORD_NONE)
				psctl |= (1 << (8 + i));
		}

		so_data(so, psctl);
	} else {
		so_data(so, 0);
	}

	so_ref(so, &rsso->so);
	so_ref(NULL, &so);
	rsso->pipe = *cso;
	return (void *)rsso;
}
static boolean
nv30_state_viewport_validate(struct nv30_context *nv30)
{
	struct pipe_viewport_state *vpt = &nv30->viewport;
	struct nouveau_stateobj *so;
	unsigned bypass;

	if (/*nv30->render_mode == HW &&*/
	    !nv30->rasterizer->pipe.bypass_vs_clip_and_viewport)
		bypass = 0;
	else
		bypass = 1;

	if (nv30->state.hw[NV30_STATE_VIEWPORT] &&
	    (bypass || !(nv30->dirty & NV30_NEW_VIEWPORT)) &&
	    nv30->state.viewport_bypass == bypass)
		return FALSE;
	nv30->state.viewport_bypass = bypass;

	so = so_new(11, 0);
	if (!bypass) {
		so_method(so, nv30->screen->rankine,
			  NV34TCL_VIEWPORT_TRANSLATE_X, 8);
		so_data  (so, fui(vpt->translate[0]));
		so_data  (so, fui(vpt->translate[1]));
		so_data  (so, fui(vpt->translate[2]));
		so_data  (so, fui(vpt->translate[3]));
		so_data  (so, fui(vpt->scale[0]));
		so_data  (so, fui(vpt->scale[1]));
		so_data  (so, fui(vpt->scale[2]));
		so_data  (so, fui(vpt->scale[3]));
/*		so_method(so, nv30->screen->rankine, 0x1d78, 1);
		so_data  (so, 1);
*/	} else {
		so_method(so, nv30->screen->rankine,
			  NV34TCL_VIEWPORT_TRANSLATE_X, 8);
		so_data  (so, fui(0.0));
		so_data  (so, fui(0.0));
		so_data  (so, fui(0.0));
		so_data  (so, fui(0.0));
		so_data  (so, fui(1.0));
		so_data  (so, fui(1.0));
		so_data  (so, fui(1.0));
		so_data  (so, fui(0.0));
		/* Not entirely certain what this is yet.  The DDX uses this
		 * value also as it fixes rendering when you pass
		 * pre-transformed vertices to the GPU.  My best gusss is that
		 * this bypasses some culling/clipping stage.  Might be worth
		 * noting that points/lines are uneffected by whatever this
		 * value fixes, only filled polygons are effected.
		 */
/*		so_method(so, nv30->screen->rankine, 0x1d78, 1);
		so_data  (so, 0x110);
*/	}
	/* TODO/FIXME: never saw value 0x0110 in renouveau dumps, only 0x0001 */
	so_method(so, nv30->screen->rankine, 0x1d78, 1);
	so_data  (so, 1);

	so_ref(so, &nv30->state.hw[NV30_STATE_VIEWPORT]);
	so_ref(NULL, &so);
	return TRUE;
}
Beispiel #19
0
static boolean
nv30_vertprog_validate(struct nv30_context *nv30)
{ 
	struct pipe_screen *pscreen = nv30->pipe.screen;
	struct nouveau_grobj *rankine = nv30->screen->rankine;
	struct nv30_vertex_program *vp;
	struct pipe_buffer *constbuf;
	boolean upload_code = FALSE, upload_data = FALSE;
	int i;

	vp = nv30->vertprog;
	constbuf = nv30->constbuf[PIPE_SHADER_VERTEX];

	/* Translate TGSI shader into hw bytecode */
	if (!vp->translated) {
		nv30_vertprog_translate(nv30, vp);
		if (!vp->translated)
			return FALSE;
	}

	/* Allocate hw vtxprog exec slots */
	if (!vp->exec) {
		struct nouveau_resource *heap = nv30->screen->vp_exec_heap;
		struct nouveau_stateobj *so;
		uint vplen = vp->nr_insns;

		if (nouveau_resource_alloc(heap, vplen, vp, &vp->exec)) {
			while (heap->next && heap->size < vplen) {
				struct nv30_vertex_program *evict;
				
				evict = heap->next->priv;
				nouveau_resource_free(&evict->exec);
			}

			if (nouveau_resource_alloc(heap, vplen, vp, &vp->exec))
				assert(0);
		}

		so = so_new(2, 0);
		so_method(so, rankine, NV34TCL_VP_START_FROM_ID, 1);
		so_data  (so, vp->exec->start);
		so_ref(so, &vp->so);
		so_ref(NULL, &so);

		upload_code = TRUE;
	}

	/* Allocate hw vtxprog const slots */
	if (vp->nr_consts && !vp->data) {
		struct nouveau_resource *heap = nv30->screen->vp_data_heap;

		if (nouveau_resource_alloc(heap, vp->nr_consts, vp, &vp->data)) {
			while (heap->next && heap->size < vp->nr_consts) {
				struct nv30_vertex_program *evict;
				
				evict = heap->next->priv;
				nouveau_resource_free(&evict->data);
			}

			if (nouveau_resource_alloc(heap, vp->nr_consts, vp,
						   &vp->data))
				assert(0);
		}

		/*XXX: handle this some day */
		assert(vp->data->start >= vp->data_start_min);

		upload_data = TRUE;
		if (vp->data_start != vp->data->start)
			upload_code = TRUE;
	}

	/* If exec or data segments moved we need to patch the program to
	 * fixup offsets and register IDs.
	 */
	if (vp->exec_start != vp->exec->start) {
		for (i = 0; i < vp->nr_insns; i++) {
			struct nv30_vertex_program_exec *vpi = &vp->insns[i];

			if (vpi->has_branch_offset) {
				assert(0);
			}
		}

		vp->exec_start = vp->exec->start;
	}

	if (vp->nr_consts && vp->data_start != vp->data->start) {
		for (i = 0; i < vp->nr_insns; i++) {
			struct nv30_vertex_program_exec *vpi = &vp->insns[i];

			if (vpi->const_index >= 0) {
				vpi->data[1] &= ~NV30_VP_INST_CONST_SRC_MASK;
				vpi->data[1] |=
					(vpi->const_index + vp->data->start) <<
					NV30_VP_INST_CONST_SRC_SHIFT;

			}
		}

		vp->data_start = vp->data->start;
	}

	/* Update + Upload constant values */
	if (vp->nr_consts) {
		float *map = NULL;

		if (constbuf) {
			map = pipe_buffer_map(pscreen, constbuf,
					      PIPE_BUFFER_USAGE_CPU_READ);
		}

		for (i = 0; i < vp->nr_consts; i++) {
			struct nv30_vertex_program_data *vpd = &vp->consts[i];

			if (vpd->index >= 0) {
				if (!upload_data &&
				    !memcmp(vpd->value, &map[vpd->index * 4],
					    4 * sizeof(float)))
					continue;
				memcpy(vpd->value, &map[vpd->index * 4],
				       4 * sizeof(float));
			}

			BEGIN_RING(rankine, NV34TCL_VP_UPLOAD_CONST_ID, 5);
			OUT_RING  (i + vp->data->start);
			OUT_RINGp ((uint32_t *)vpd->value, 4);
		}

		if (constbuf)
			pipe_buffer_unmap(pscreen, constbuf);
	}

	/* Upload vtxprog */
	if (upload_code) {
#if 0
		for (i = 0; i < vp->nr_insns; i++) {
			NOUVEAU_MSG("VP inst %d: 0x%08x 0x%08x 0x%08x 0x%08x\n",
				i, vp->insns[i].data[0], vp->insns[i].data[1],
				vp->insns[i].data[2], vp->insns[i].data[3]);
		}
#endif
		BEGIN_RING(rankine, NV34TCL_VP_UPLOAD_FROM_ID, 1);
		OUT_RING  (vp->exec->start);
		for (i = 0; i < vp->nr_insns; i++) {
			BEGIN_RING(rankine, NV34TCL_VP_UPLOAD_INST(0), 4);
			OUT_RINGp (vp->insns[i].data, 4);
		}
	}

	if (vp->so != nv30->state.hw[NV30_STATE_VERTPROG]) {
		so_ref(vp->so, &nv30->state.hw[NV30_STATE_VERTPROG]);
		return TRUE;
	}

	return FALSE;
}
Beispiel #20
0
struct pipe_screen *
nv30_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
{
	struct nv30_screen *screen = CALLOC_STRUCT(nv30_screen);
	struct nouveau_channel *chan;
	struct pipe_screen *pscreen;
	struct nouveau_stateobj *so;
	unsigned rankine_class = 0;
	int ret, i;

	if (!screen)
		return NULL;
	pscreen = &screen->base.base;

	ret = nouveau_screen_init(&screen->base, dev);
	if (ret) {
		nv30_screen_destroy(pscreen);
		return NULL;
	}
	chan = screen->base.channel;

	pscreen->winsys = ws;
	pscreen->destroy = nv30_screen_destroy;
	pscreen->get_param = nv30_screen_get_param;
	pscreen->get_paramf = nv30_screen_get_paramf;
	pscreen->is_format_supported = nv30_screen_surface_format_supported;
	pscreen->context_create = nv30_create;

	nv30_screen_init_miptree_functions(pscreen);
	nv30_screen_init_transfer_functions(pscreen);

	/* 3D object */
	switch (dev->chipset & 0xf0) {
	case 0x30:
		if (NV30TCL_CHIPSET_3X_MASK & (1 << (dev->chipset & 0x0f)))
			rankine_class = 0x0397;
		else
		if (NV34TCL_CHIPSET_3X_MASK & (1 << (dev->chipset & 0x0f)))
			rankine_class = 0x0697;
		else
		if (NV35TCL_CHIPSET_3X_MASK & (1 << (dev->chipset & 0x0f)))
			rankine_class = 0x0497;
		break;
	default:
		break;
	}

	if (!rankine_class) {
		NOUVEAU_ERR("Unknown nv3x chipset: nv%02x\n", dev->chipset);
		return NULL;
	}

	ret = nouveau_grobj_alloc(chan, 0xbeef3097, rankine_class,
				  &screen->rankine);
	if (ret) {
		NOUVEAU_ERR("Error creating 3D object: %d\n", ret);
		return FALSE;
	}

	/* 2D engine setup */
	screen->eng2d = nv04_surface_2d_init(&screen->base);
	screen->eng2d->buf = nv30_surface_buffer;

	/* Notifier for sync purposes */
	ret = nouveau_notifier_alloc(chan, 0xbeef0301, 1, &screen->sync);
	if (ret) {
		NOUVEAU_ERR("Error creating notifier object: %d\n", ret);
		nv30_screen_destroy(pscreen);
		return NULL;
	}

	/* Query objects */
	ret = nouveau_notifier_alloc(chan, 0xbeef0302, 32, &screen->query);
	if (ret) {
		NOUVEAU_ERR("Error initialising query objects: %d\n", ret);
		nv30_screen_destroy(pscreen);
		return NULL;
	}

	ret = nouveau_resource_init(&screen->query_heap, 0, 32);
	if (ret) {
		NOUVEAU_ERR("Error initialising query object heap: %d\n", ret);
		nv30_screen_destroy(pscreen);
		return NULL;
	}

	/* Vtxprog resources */
	if (nouveau_resource_init(&screen->vp_exec_heap, 0, 256) ||
	    nouveau_resource_init(&screen->vp_data_heap, 0, 256)) {
		nv30_screen_destroy(pscreen);
		return NULL;
	}

	/* Static rankine initialisation */
	so = so_new(36, 60, 0);
	so_method(so, screen->rankine, NV34TCL_DMA_NOTIFY, 1);
	so_data  (so, screen->sync->handle);
	so_method(so, screen->rankine, NV34TCL_DMA_TEXTURE0, 2);
	so_data  (so, chan->vram->handle);
	so_data  (so, chan->gart->handle);
	so_method(so, screen->rankine, NV34TCL_DMA_COLOR1, 1);
	so_data  (so, chan->vram->handle);
	so_method(so, screen->rankine, NV34TCL_DMA_COLOR0, 2);
	so_data  (so, chan->vram->handle);
	so_data  (so, chan->vram->handle);
	so_method(so, screen->rankine, NV34TCL_DMA_VTXBUF0, 2);
	so_data  (so, chan->vram->handle);
	so_data  (so, chan->gart->handle);
/*	so_method(so, screen->rankine, NV34TCL_DMA_FENCE, 2);
	so_data  (so, 0);
	so_data  (so, screen->query->handle);*/
	so_method(so, screen->rankine, NV34TCL_DMA_IN_MEMORY7, 1);
	so_data  (so, chan->vram->handle);
	so_method(so, screen->rankine, NV34TCL_DMA_IN_MEMORY8, 1);
	so_data  (so, chan->vram->handle);

	for (i=1; i<8; i++) {
		so_method(so, screen->rankine, NV34TCL_VIEWPORT_CLIP_HORIZ(i), 1);
		so_data  (so, 0);
		so_method(so, screen->rankine, NV34TCL_VIEWPORT_CLIP_VERT(i), 1);
		so_data  (so, 0);
	}

	so_method(so, screen->rankine, 0x220, 1);
	so_data  (so, 1);

	so_method(so, screen->rankine, 0x03b0, 1);
	so_data  (so, 0x00100000);
	so_method(so, screen->rankine, 0x1454, 1);
	so_data  (so, 0);
	so_method(so, screen->rankine, 0x1d80, 1);
	so_data  (so, 3);
	so_method(so, screen->rankine, 0x1450, 1);
	so_data  (so, 0x00030004);

	/* NEW */
	so_method(so, screen->rankine, 0x1e98, 1);
	so_data  (so, 0);
	so_method(so, screen->rankine, 0x17e0, 3);
	so_data  (so, fui(0.0));
	so_data  (so, fui(0.0));
	so_data  (so, fui(1.0));
	so_method(so, screen->rankine, 0x1f80, 16);
	for (i=0; i<16; i++) {
		so_data  (so, (i==8) ? 0x0000ffff : 0);
	}

	so_method(so, screen->rankine, 0x120, 3);
	so_data  (so, 0);
	so_data  (so, 1);
	so_data  (so, 2);

	so_method(so, screen->rankine, 0x1d88, 1);
	so_data  (so, 0x00001200);

	so_method(so, screen->rankine, NV34TCL_RC_ENABLE, 1);
	so_data  (so, 0);

	so_method(so, screen->rankine, NV34TCL_DEPTH_RANGE_NEAR, 2);
	so_data  (so, fui(0.0));
	so_data  (so, fui(1.0));

	so_method(so, screen->rankine, NV34TCL_MULTISAMPLE_CONTROL, 1);
	so_data  (so, 0xffff0000);

	/* enables use of vp rather than fixed-function somehow */
	so_method(so, screen->rankine, 0x1e94, 1);
	so_data  (so, 0x13);

	so_emit(chan, so);
	so_ref(NULL, &so);
	nouveau_pushbuf_flush(chan, 0);

	return pscreen;
}
Beispiel #21
0
static void *
nv50_blend_state_create(struct pipe_context *pipe,
			const struct pipe_blend_state *cso)
{
	struct nouveau_stateobj *so = so_new(64, 0);
	struct nouveau_grobj *tesla = nv50_context(pipe)->screen->tesla;
	struct nv50_blend_stateobj *bso = CALLOC_STRUCT(nv50_blend_stateobj);
	unsigned cmask = 0, i;

	/*XXX ignored:
	 * 	- dither
	 */

	if (cso->blend_enable == 0) {
		so_method(so, tesla, NV50TCL_BLEND_ENABLE(0), 8);
		for (i = 0; i < 8; i++)
			so_data(so, 0);
	} else {
		so_method(so, tesla, NV50TCL_BLEND_ENABLE(0), 8);
		for (i = 0; i < 8; i++)
			so_data(so, 1);
		so_method(so, tesla, NV50TCL_BLEND_EQUATION_RGB, 5);
		so_data  (so, nvgl_blend_eqn(cso->rgb_func));
		so_data  (so, 0x4000 | nvgl_blend_func(cso->rgb_src_factor));
		so_data  (so, 0x4000 | nvgl_blend_func(cso->rgb_dst_factor));
		so_data  (so, nvgl_blend_eqn(cso->alpha_func));
		so_data  (so, 0x4000 | nvgl_blend_func(cso->alpha_src_factor));
		so_method(so, tesla, NV50TCL_BLEND_FUNC_DST_ALPHA, 1);
		so_data  (so, 0x4000 | nvgl_blend_func(cso->alpha_dst_factor));
	}

	if (cso->logicop_enable == 0 ) {
		so_method(so, tesla, NV50TCL_LOGIC_OP_ENABLE, 1);
		so_data  (so, 0);
	} else {
		so_method(so, tesla, NV50TCL_LOGIC_OP_ENABLE, 2);
		so_data  (so, 1);
		so_data  (so, nvgl_logicop_func(cso->logicop_func));
	}

	if (cso->colormask & PIPE_MASK_R)
		cmask |= (1 << 0);
	if (cso->colormask & PIPE_MASK_G)
		cmask |= (1 << 4);
	if (cso->colormask & PIPE_MASK_B)
		cmask |= (1 << 8);
	if (cso->colormask & PIPE_MASK_A)
		cmask |= (1 << 12);
	so_method(so, tesla, NV50TCL_COLOR_MASK(0), 8);
	for (i = 0; i < 8; i++)
		so_data(so, cmask);

	bso->pipe = *cso;
	so_ref(so, &bso->so);
	so_ref(NULL, &so);
	return (void *)bso;
}
Beispiel #22
0
static void *
nv40_depth_stencil_alpha_state_create(struct pipe_context *pipe,
			const struct pipe_depth_stencil_alpha_state *cso)
{
	struct nv40_context *nv40 = nv40_context(pipe);
	struct nv40_zsa_state *zsaso = CALLOC(1, sizeof(*zsaso));
	struct nouveau_stateobj *so = so_new(32, 0);
	struct nouveau_grobj *curie = nv40->screen->curie;

	so_method(so, curie, NV40TCL_DEPTH_FUNC, 3);
	so_data  (so, nvgl_comparison_op(cso->depth.func));
	so_data  (so, cso->depth.writemask ? 1 : 0);
	so_data  (so, cso->depth.enabled ? 1 : 0);

	so_method(so, curie, NV40TCL_ALPHA_TEST_ENABLE, 3);
	so_data  (so, cso->alpha.enabled ? 1 : 0);
	so_data  (so, nvgl_comparison_op(cso->alpha.func));
	so_data  (so, float_to_ubyte(cso->alpha.ref_value));

	if (cso->stencil[0].enabled) {
		so_method(so, curie, NV40TCL_STENCIL_FRONT_ENABLE, 8);
		so_data  (so, cso->stencil[0].enabled ? 1 : 0);
		so_data  (so, cso->stencil[0].writemask);
		so_data  (so, nvgl_comparison_op(cso->stencil[0].func));
		so_data  (so, cso->stencil[0].ref_value);
		so_data  (so, cso->stencil[0].valuemask);
		so_data  (so, nvgl_stencil_op(cso->stencil[0].fail_op));
		so_data  (so, nvgl_stencil_op(cso->stencil[0].zfail_op));
		so_data  (so, nvgl_stencil_op(cso->stencil[0].zpass_op));
	} else {
		so_method(so, curie, NV40TCL_STENCIL_FRONT_ENABLE, 1);
		so_data  (so, 0);
	}

	if (cso->stencil[1].enabled) {
		so_method(so, curie, NV40TCL_STENCIL_BACK_ENABLE, 8);
		so_data  (so, cso->stencil[1].enabled ? 1 : 0);
		so_data  (so, cso->stencil[1].writemask);
		so_data  (so, nvgl_comparison_op(cso->stencil[1].func));
		so_data  (so, cso->stencil[1].ref_value);
		so_data  (so, cso->stencil[1].valuemask);
		so_data  (so, nvgl_stencil_op(cso->stencil[1].fail_op));
		so_data  (so, nvgl_stencil_op(cso->stencil[1].zfail_op));
		so_data  (so, nvgl_stencil_op(cso->stencil[1].zpass_op));
	} else {
		so_method(so, curie, NV40TCL_STENCIL_BACK_ENABLE, 1);
		so_data  (so, 0);
	}

	so_ref(so, &zsaso->so);
	so_ref(NULL, &so);
	zsaso->pipe = *cso;
	return (void *)zsaso;
}
Beispiel #23
0
struct pipe_screen *
nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
{
	struct nv50_screen *screen = CALLOC_STRUCT(nv50_screen);
	struct nouveau_channel *chan;
	struct pipe_screen *pscreen;
	struct nouveau_stateobj *so;
	unsigned chipset = dev->chipset;
	unsigned tesla_class = 0;
	int ret, i;

	if (!screen)
		return NULL;
	pscreen = &screen->base.base;

	ret = nouveau_screen_init(&screen->base, dev);
	if (ret) {
		nv50_screen_destroy(pscreen);
		return NULL;
	}
	chan = screen->base.channel;

	pscreen->winsys = ws;
	pscreen->destroy = nv50_screen_destroy;
	pscreen->get_param = nv50_screen_get_param;
	pscreen->get_paramf = nv50_screen_get_paramf;
	pscreen->is_format_supported = nv50_screen_is_format_supported;
	pscreen->context_create = nv50_create;
	screen->base.pre_pipebuffer_map_callback = nv50_pre_pipebuffer_map;

	nv50_screen_init_miptree_functions(pscreen);
	nv50_transfer_init_screen_functions(pscreen);

	/* DMA engine object */
	ret = nouveau_grobj_alloc(chan, 0xbeef5039,
		NV50_MEMORY_TO_MEMORY_FORMAT, &screen->m2mf);
	if (ret) {
		NOUVEAU_ERR("Error creating M2MF object: %d\n", ret);
		nv50_screen_destroy(pscreen);
		return NULL;
	}

	/* 2D object */
	ret = nouveau_grobj_alloc(chan, 0xbeef502d, NV50_2D, &screen->eng2d);
	if (ret) {
		NOUVEAU_ERR("Error creating 2D object: %d\n", ret);
		nv50_screen_destroy(pscreen);
		return NULL;
	}

	/* 3D object */
	switch (chipset & 0xf0) {
	case 0x50:
		tesla_class = NV50TCL;
		break;
	case 0x80:
	case 0x90:
		tesla_class = NV84TCL;
		break;
	case 0xa0:
		switch (chipset) {
		case 0xa0:
		case 0xaa:
		case 0xac:
			tesla_class = NVA0TCL;
			break;
		default:
			tesla_class = NVA8TCL;
			break;
		}
		break;
	default:
		NOUVEAU_ERR("Not a known NV50 chipset: NV%02x\n", chipset);
		nv50_screen_destroy(pscreen);
		return NULL;
	}

	ret = nouveau_grobj_alloc(chan, 0xbeef5097, tesla_class,
		&screen->tesla);
	if (ret) {
		NOUVEAU_ERR("Error creating 3D object: %d\n", ret);
		nv50_screen_destroy(pscreen);
		return NULL;
	}

	/* Sync notifier */
	ret = nouveau_notifier_alloc(chan, 0xbeef0301, 1, &screen->sync);
	if (ret) {
		NOUVEAU_ERR("Error creating notifier object: %d\n", ret);
		nv50_screen_destroy(pscreen);
		return NULL;
	}

	/* Static M2MF init */
	so = so_new(1, 3, 0);
	so_method(so, screen->m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3);
	so_data  (so, screen->sync->handle);
	so_data  (so, chan->vram->handle);
	so_data  (so, chan->vram->handle);
	so_emit(chan, so);
	so_ref (NULL, &so);

	/* Static 2D init */
	so = so_new(4, 7, 0);
	so_method(so, screen->eng2d, NV50_2D_DMA_NOTIFY, 4);
	so_data  (so, screen->sync->handle);
	so_data  (so, chan->vram->handle);
	so_data  (so, chan->vram->handle);
	so_data  (so, chan->vram->handle);
	so_method(so, screen->eng2d, NV50_2D_OPERATION, 1);
	so_data  (so, NV50_2D_OPERATION_SRCCOPY);
	so_method(so, screen->eng2d, NV50_2D_CLIP_ENABLE, 1);
	so_data  (so, 0);
	so_method(so, screen->eng2d, 0x0888, 1);
	so_data  (so, 1);
	so_emit(chan, so);
	so_ref(NULL, &so);

	/* Static tesla init */
	so = so_new(47, 95, 24);

	so_method(so, screen->tesla, NV50TCL_COND_MODE, 1);
	so_data  (so, NV50TCL_COND_MODE_ALWAYS);
	so_method(so, screen->tesla, NV50TCL_DMA_NOTIFY, 1);
	so_data  (so, screen->sync->handle);
	so_method(so, screen->tesla, NV50TCL_DMA_ZETA, 11);
	for (i = 0; i < 11; i++)
		so_data(so, chan->vram->handle);
	so_method(so, screen->tesla, NV50TCL_DMA_COLOR(0),
				     NV50TCL_DMA_COLOR__SIZE);
	for (i = 0; i < NV50TCL_DMA_COLOR__SIZE; i++)
		so_data(so, chan->vram->handle);
	so_method(so, screen->tesla, NV50TCL_RT_CONTROL, 1);
	so_data  (so, 1);

	/* activate all 32 lanes (threads) in a warp */
	so_method(so, screen->tesla, NV50TCL_WARP_HALVES, 1);
	so_data  (so, 0x2);
	so_method(so, screen->tesla, 0x1400, 1);
	so_data  (so, 0xf);

	/* max TIC (bits 4:8) & TSC (ignored) bindings, per program type */
	for (i = 0; i < 3; ++i) {
		so_method(so, screen->tesla, NV50TCL_TEX_LIMITS(i), 1);
		so_data  (so, 0x54);
	}

	/* origin is top left (set to 1 for bottom left) */
	so_method(so, screen->tesla, NV50TCL_Y_ORIGIN_BOTTOM, 1);
	so_data  (so, 0);
	so_method(so, screen->tesla, NV50TCL_VP_REG_ALLOC_RESULT, 1);
	so_data  (so, 8);

	/* constant buffers for immediates and VP/FP parameters */
	ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, (32 * 4) * 4,
			     &screen->constbuf_misc[0]);
	if (ret) {
		nv50_screen_destroy(pscreen);
		return NULL;
	}

	for (i = 0; i < 3; i++) {
		ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, (256 * 4) * 4,
				     &screen->constbuf_parm[i]);
		if (ret) {
			nv50_screen_destroy(pscreen);
			return NULL;
		}
	}

	if (nouveau_resource_init(&screen->immd_heap[0], 0, 128) ||
	    nouveau_resource_init(&screen->parm_heap[0], 0, 512) ||
	    nouveau_resource_init(&screen->parm_heap[1], 0, 512))
	{
		NOUVEAU_ERR("Error initialising constant buffers.\n");
		nv50_screen_destroy(pscreen);
		return NULL;
	}

	/*
	// map constant buffers:
	//  B = buffer ID (maybe more than 1 byte)
	//  N = CB index used in shader instruction
	//  P = program type (0 = VP, 2 = GP, 3 = FP)
	so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
	so_data  (so, 0x000BBNP1);
	*/

	so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3);
	so_reloc (so, screen->constbuf_misc[0], 0, NOUVEAU_BO_VRAM |
		  NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
	so_reloc (so, screen->constbuf_misc[0], 0, NOUVEAU_BO_VRAM |
		  NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
	so_data  (so, (NV50_CB_PMISC << 16) | 0x00000200);
	so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
	so_data  (so, 0x00000001 | (NV50_CB_PMISC << 12));
	so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
	so_data  (so, 0x00000021 | (NV50_CB_PMISC << 12));
	so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
	so_data  (so, 0x00000031 | (NV50_CB_PMISC << 12));

	/* bind auxiliary constbuf to immediate data bo */
	so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3);
	so_reloc (so, screen->constbuf_misc[0], (128 * 4) * 4,
		  NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
	so_reloc (so, screen->constbuf_misc[0], (128 * 4) * 4,
		  NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
	so_data  (so, (NV50_CB_AUX << 16) | 0x00000200);
	so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
	so_data  (so, 0x00000201 | (NV50_CB_AUX << 12));
	so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
	so_data  (so, 0x00000221 | (NV50_CB_AUX << 12));

	so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3);
	so_reloc (so, screen->constbuf_parm[PIPE_SHADER_VERTEX], 0,
		  NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
	so_reloc (so, screen->constbuf_parm[PIPE_SHADER_VERTEX], 0,
		  NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
	so_data  (so, (NV50_CB_PVP << 16) | 0x00000800);
	so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
	so_data  (so, 0x00000101 | (NV50_CB_PVP << 12));

	so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3);
	so_reloc (so, screen->constbuf_parm[PIPE_SHADER_GEOMETRY], 0,
		  NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
	so_reloc (so, screen->constbuf_parm[PIPE_SHADER_GEOMETRY], 0,
		  NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
	so_data  (so, (NV50_CB_PGP << 16) | 0x00000800);
	so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
	so_data  (so, 0x00000121 | (NV50_CB_PGP << 12));

	so_method(so, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3);
	so_reloc (so, screen->constbuf_parm[PIPE_SHADER_FRAGMENT], 0,
		  NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
	so_reloc (so, screen->constbuf_parm[PIPE_SHADER_FRAGMENT], 0,
		  NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
	so_data  (so, (NV50_CB_PFP << 16) | 0x00000800);
	so_method(so, screen->tesla, NV50TCL_SET_PROGRAM_CB, 1);
	so_data  (so, 0x00000131 | (NV50_CB_PFP << 12));

	ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, PIPE_SHADER_TYPES*32*32,
			     &screen->tic);
	if (ret) {
		nv50_screen_destroy(pscreen);
		return NULL;
	}

	so_method(so, screen->tesla, NV50TCL_TIC_ADDRESS_HIGH, 3);
	so_reloc (so, screen->tic, 0, NOUVEAU_BO_VRAM |
		  NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
	so_reloc (so, screen->tic, 0, NOUVEAU_BO_VRAM |
		  NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
	so_data  (so, PIPE_SHADER_TYPES * 32 - 1);

	ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, PIPE_SHADER_TYPES*32*32,
			     &screen->tsc);
	if (ret) {
		nv50_screen_destroy(pscreen);
		return NULL;
	}

	so_method(so, screen->tesla, NV50TCL_TSC_ADDRESS_HIGH, 3);
	so_reloc (so, screen->tsc, 0, NOUVEAU_BO_VRAM |
		  NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
	so_reloc (so, screen->tsc, 0, NOUVEAU_BO_VRAM |
		  NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
	so_data  (so, 0x00000000); /* ignored if TSC_LINKED (0x1234) = 1 */


	/* Vertex array limits - max them out */
	for (i = 0; i < 16; i++) {
		so_method(so, screen->tesla, NV50TCL_VERTEX_ARRAY_LIMIT_HIGH(i), 2);
		so_data  (so, 0x000000ff);
		so_data  (so, 0xffffffff);
	}

	so_method(so, screen->tesla, NV50TCL_DEPTH_RANGE_NEAR(0), 2);
	so_data  (so, fui(0.0));
	so_data  (so, fui(1.0));

	/* no dynamic combination of TIC & TSC entries => only BIND_TIC used */
	so_method(so, screen->tesla, NV50TCL_LINKED_TSC, 1);
	so_data  (so, 1);

	/* activate first scissor rectangle */
	so_method(so, screen->tesla, NV50TCL_SCISSOR_ENABLE(0), 1);
	so_data  (so, 1);

	so_method(so, screen->tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
	so_data  (so, 1); /* default edgeflag to TRUE */

	so_emit(chan, so);
	so_ref (so, &screen->static_init);
	so_ref (NULL, &so);
	nouveau_pushbuf_flush(chan, 0);

	return pscreen;
}