nv50: import current "state of the art" nv50 code

This commit is contained in:
Ben Skeggs
2008-06-01 22:41:40 +10:00
parent b6478021d5
commit f722fd937d
9 changed files with 1017 additions and 13 deletions
+1
View File
@@ -9,6 +9,7 @@ DRIVER_SOURCES = \
nv50_draw.c \
nv50_miptree.c \
nv50_query.c \
nv50_program.c \
nv50_screen.c \
nv50_state.c \
nv50_state_validate.c \
+18
View File
@@ -9,6 +9,7 @@
#include "nouveau/nouveau_winsys.h"
#include "nouveau/nouveau_gldefs.h"
#include "nouveau/nouveau_stateobj.h"
#define NOUVEAU_PUSH_CONTEXT(ctx) \
struct nv50_screen *ctx = nv50->screen
@@ -30,6 +31,9 @@
#define NV50_NEW_VIEWPORT (1 << 5)
#define NV50_NEW_RASTERIZER (1 << 6)
#define NV50_NEW_FRAMEBUFFER (1 << 7)
#define NV50_NEW_VERTPROG (1 << 8)
#define NV50_NEW_FRAGPROG (1 << 9)
#define NV50_NEW_ARRAYS (1 << 10)
struct nv50_blend_stateobj {
struct pipe_blend_state pipe;
@@ -63,6 +67,13 @@ struct nv50_context {
struct pipe_scissor_state scissor;
struct pipe_viewport_state viewport;
struct pipe_framebuffer_state framebuffer;
struct nv50_program *vertprog;
struct nv50_program *fragprog;
struct pipe_buffer *constbuf[PIPE_SHADER_TYPES];
struct pipe_vertex_buffer vtxbuf[PIPE_MAX_ATTRIBS];
unsigned vtxbuf_nr;
struct pipe_vertex_element vtxelt[PIPE_MAX_ATTRIBS];
unsigned vtxelt_nr;
};
static INLINE struct nv50_context *
@@ -88,11 +99,18 @@ extern boolean nv50_draw_elements(struct pipe_context *pipe,
unsigned indexSize,
unsigned mode, unsigned start,
unsigned count);
extern void nv50_vbo_validate(struct nv50_context *nv50);
/* nv50_clear.c */
extern void nv50_clear(struct pipe_context *pipe, struct pipe_surface *ps,
unsigned clearValue);
/* nv50_program.c */
extern void nv50_vertprog_validate(struct nv50_context *nv50);
extern void nv50_fragprog_validate(struct nv50_context *nv50);
extern void nv50_program_destroy(struct nv50_context *nv50, struct nv50_program *p);
/* nv50_state_validate.c */
extern boolean nv50_state_validate(struct nv50_context *nv50);
#endif
+742
View File
@@ -0,0 +1,742 @@
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_state.h"
#include "pipe/p_inlines.h"
#include "pipe/p_shader_tokens.h"
#include "tgsi/util/tgsi_parse.h"
#include "tgsi/util/tgsi_util.h"
#include "nv50_context.h"
#include "nv50_state.h"
#define OP_MOV 0x001
#define OP_RCP 0x009
#define OP_ADD 0x00b
#define OP_MUL 0x00c
#define NV50_SU_MAX_TEMP 64
struct nv50_reg {
enum {
P_TEMP,
P_ATTR,
P_RESULT,
P_CONST,
P_IMMD
} type;
int index;
int hw;
};
struct nv50_pc {
struct nv50_program *p;
/* hw resources */
struct nv50_reg *r_temp[NV50_SU_MAX_TEMP];
/* tgsi resources */
struct nv50_reg *temp;
int temp_nr;
struct nv50_reg *attr;
int attr_nr;
struct nv50_reg *result;
int result_nr;
struct nv50_reg *param;
int param_nr;
struct nv50_reg *immd;
float *immd_buf;
int immd_nr;
};
static void
alloc_reg(struct nv50_pc *pc, struct nv50_reg *reg)
{
int i;
if (reg->type != P_TEMP || reg->hw >= 0)
return;
for (i = 0; i < NV50_SU_MAX_TEMP; i++) {
if (!(pc->r_temp[i])) {
pc->r_temp[i] = reg;
reg->hw = i;
if (pc->p->cfg.vp.high_temp < (i + 1))
pc->p->cfg.vp.high_temp = i + 1;
return;
}
}
assert(0);
}
static struct nv50_reg *
alloc_temp(struct nv50_pc *pc, struct nv50_reg *dst)
{
struct nv50_reg *r;
int i;
if (dst && dst->type == P_TEMP && dst->hw == -1)
return dst;
for (i = 0; i < NV50_SU_MAX_TEMP; i++) {
if (!pc->r_temp[i]) {
r = CALLOC_STRUCT(nv50_reg);
r->type = P_TEMP;
r->index = -1;
r->hw = i;
pc->r_temp[i] = r;
return r;
}
}
assert(0);
return NULL;
}
static void
free_temp(struct nv50_pc *pc, struct nv50_reg *r)
{
if (r->index == -1) {
FREE(pc->r_temp[r->hw]);
pc->r_temp[r->hw] = NULL;
}
}
#if 0
static struct nv50_reg *
constant(struct nv50_pc *pc, int pipe, int c, float v)
{
struct nv50_reg *r = CALLOC_STRUCT(nv50_reg);
struct nv50_program *p = pc->p;
struct nv50_program_data *pd;
int idx;
if (pipe >= 0) {
for (idx = 0; idx < p->nr_consts; idx++) {
if (p->consts[idx].index == pipe)
return nv40_sr(NV40SR_CONST, idx);
}
}
idx = p->nr_consts++;
p->consts = realloc(p->consts, sizeof(*pd) * p->nr_consts);
pd = &p->consts[idx];
pd->index = pipe;
pd->component = c;
pd->value = v;
return nv40_sr(NV40SR_CONST, idx);
}
#endif
static void
emit(struct nv50_pc *pc, unsigned op, struct nv50_reg *dst,
struct nv50_reg *src0, struct nv50_reg *src1, struct nv50_reg *src2)
{
struct nv50_program *p = pc->p;
struct nv50_reg *tmp = NULL, *tmp2 = NULL;
unsigned inst[2] = { 0, 0 };
/* Grr.. Fun restrictions on where attribs can be sourced from.. */
if (src1 && src1->type == P_ATTR) {
tmp = alloc_temp(pc, dst);
emit(pc, 1, tmp, src1, NULL, NULL);
src1 = tmp;
}
if (src2 && src2->type == P_ATTR) {
tmp2 = alloc_temp(pc, dst);
emit(pc, 1, tmp2, src2, NULL, NULL);
src2 = tmp2;
}
/* Get this out of the way first. What type of opcode do we
* want/need to build?
*/
if ((op & 0x3f0) || dst->type == P_RESULT ||
(src0 && src0->type == P_ATTR) || src1 || src2)
inst[0] |= 0x00000001;
if (inst[0] & 0x00000001) {
inst[0] |= ((op & 0xf) << 28);
inst[1] |= ((op >> 4) << 26);
alloc_reg(pc, dst);
if (dst->type == P_RESULT)
inst[1] |= 0x00000008;
inst[0] |= (dst->hw << 2);
if (src0) {
if (src0->type == P_ATTR)
inst[1] |= 0x00200000;
else
if (src0->type == P_CONST || src0->type == P_IMMD)
assert(0);
alloc_reg(pc, src0);
inst[0] |= (src0->hw << 9);
}
if (src1) {
if (src1->type == P_CONST || src1->type == P_IMMD) {
inst[0] |= 0x00800000; /* src1 is const */
/*XXX: does src1 come from "src2" now? */
alloc_reg(pc, src1);
inst[0] |= (src1->hw << 16);
} else {
alloc_reg(pc, src1);
if (op == 0xc || op == 0xe)
inst[0] |= (src1->hw << 16);
else
inst[1] |= (src1->hw << 14);
}
} else {
inst[1] |= 0x0003c000; /*XXX FIXME */
}
if (src2) {
if (src2->type == P_CONST || src2->type == P_IMMD) {
inst[0] |= 0x01000000; /* src2 is const */
inst[1] |= (src2->hw << 14);
} else {
alloc_reg(pc, src2);
if (inst[0] & 0x00800000 || op ==0xe)
inst[1] |= (src2->hw << 14);
else
inst[0] |= (src2->hw << 16);
}
}
/*XXX: FIXME */
if (op == 0xb || op == 0xc || op == 0x9 || op == 0xe) {
/* 0x04000000 negates arg0 */
/* 0x08000000 negates arg1 */
/*XXX: true for !0xb also ? */
inst[1] |= 0x00000780;
} else {
/* 0x04000000 == arg0 32 bit, otherwise 16 bit */
inst[1] |= 0x04000780;
}
} else {
inst[0] |= ((op & 0xf) << 28);
alloc_reg(pc, dst);
inst[0] |= (dst->hw << 2);
if (src0) {
alloc_reg(pc, src0);
inst[0] |= (src0->hw << 9);
}
/*XXX: NFI if this even works - probably not.. */
if (src1) {
alloc_reg(pc, src1);
inst[0] |= (src1->hw << 16);
}
}
if (tmp) free_temp(pc, tmp);
if (tmp2) free_temp(pc, tmp2);
if (inst[0] & 1) {
p->insns_nr += 2;
p->insns = realloc(p->insns, sizeof(unsigned) * p->insns_nr);
memcpy(p->insns + (p->insns_nr - 2), inst, sizeof(unsigned)*2);
} else {
p->insns_nr += 1;
p->insns = realloc(p->insns, sizeof(unsigned) * p->insns_nr);
memcpy(p->insns + (p->insns_nr - 1), inst, sizeof(unsigned));
}
}
static struct nv50_reg *
tgsi_dst(struct nv50_pc *pc, int c, const struct tgsi_full_dst_register *dst)
{
switch (dst->DstRegister.File) {
case TGSI_FILE_TEMPORARY:
return &pc->temp[dst->DstRegister.Index * 4 + c];
case TGSI_FILE_OUTPUT:
return &pc->result[dst->DstRegister.Index * 4 + c];
case TGSI_FILE_NULL:
return NULL;
default:
break;
}
return NULL;
}
static struct nv50_reg *
tgsi_src(struct nv50_pc *pc, int c, const struct tgsi_full_src_register *src)
{
/* Handle swizzling */
switch (c) {
case 0: c = src->SrcRegister.SwizzleX; break;
case 1: c = src->SrcRegister.SwizzleY; break;
case 2: c = src->SrcRegister.SwizzleZ; break;
case 3: c = src->SrcRegister.SwizzleW; break;
default:
assert(0);
}
switch (src->SrcRegister.File) {
case TGSI_FILE_INPUT:
return &pc->attr[src->SrcRegister.Index * 4 + c];
case TGSI_FILE_TEMPORARY:
return &pc->temp[src->SrcRegister.Index * 4 + c];
case TGSI_FILE_CONSTANT:
return &pc->param[src->SrcRegister.Index * 4 + c];
case TGSI_FILE_IMMEDIATE:
return &pc->immd[src->SrcRegister.Index * 4 + c];
default:
break;
}
return NULL;
}
static boolean
nv50_program_tx_insn(struct nv50_pc *pc, const union tgsi_full_token *tok)
{
const struct tgsi_full_instruction *inst = &tok->FullInstruction;
struct nv50_reg *dst[4], *src[3][4], *none = NULL, *tmp;
unsigned mask;
int i, c;
NOUVEAU_ERR("insn %p\n", tok);
mask = inst->FullDstRegisters[0].DstRegister.WriteMask;
for (c = 0; c < 4; c++) {
if (mask & (1 << c))
dst[c] = tgsi_dst(pc, c, &inst->FullDstRegisters[0]);
else
dst[c] = NULL;
}
for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
for (c = 0; c < 4; c++)
src[i][c] = tgsi_src(pc, c, &inst->FullSrcRegisters[i]);
}
switch (inst->Instruction.Opcode) {
case TGSI_OPCODE_ADD:
for (c = 0; c < 4; c++) {
if (mask & (1 << c)) {
emit(pc, 0x0b, dst[c],
src[0][c], src[1][c], none);
}
}
break;
case TGSI_OPCODE_DP3:
tmp = alloc_temp(pc, NULL);
emit(pc, 0x0c, tmp, src[0][0], src[1][0], NULL);
emit(pc, 0x0e, tmp, src[0][1], src[1][1], tmp);
emit(pc, 0x0e, tmp, src[0][2], src[1][2], tmp);
for (c = 0; c < 4; c++) {
if (mask & (1 << c))
emit(pc, 0x01, dst[c], tmp, none, none);
}
free_temp(pc, tmp);
break;
case TGSI_OPCODE_DP4:
tmp = alloc_temp(pc, NULL);
emit(pc, 0x0c, tmp, src[0][0], src[1][0], NULL);
emit(pc, 0x0e, tmp, src[0][1], src[1][1], tmp);
emit(pc, 0x0e, tmp, src[0][2], src[1][2], tmp);
emit(pc, 0x0e, tmp, src[0][3], src[1][3], tmp);
for (c = 0; c < 4; c++) {
if (mask & (1 << c))
emit(pc, 0x01, dst[c], tmp, none, none);
}
free_temp(pc, tmp);
break;
case TGSI_OPCODE_MAD:
for (c = 0; c < 4; c++) {
if (mask & (1 << c))
emit(pc, 0x0e, dst[c],
src[0][c], src[1][c], src[2][c]);
}
break;
case TGSI_OPCODE_MOV:
for (c = 0; c < 4; c++) {
if (mask & (1 << c))
emit(pc, 0x01, dst[c], src[0][c], none, none);
}
break;
case TGSI_OPCODE_MUL:
for (c = 0; c < 4; c++) {
if (mask & (1 << c))
emit(pc, 0x0c, dst[c],
src[0][c], src[1][c], none);
}
break;
case TGSI_OPCODE_RCP:
for (c = 0; c < 4; c++) {
if (mask & (1 << c))
emit(pc, 0x09, dst[c],
src[0][c], none, none);
}
break;
case TGSI_OPCODE_END:
break;
default:
NOUVEAU_ERR("invalid opcode %d\n", inst->Instruction.Opcode);
return FALSE;
}
return TRUE;
}
static boolean
nv50_program_tx_prep(struct nv50_pc *pc)
{
struct tgsi_parse_context p;
boolean ret = FALSE;
unsigned i, c;
tgsi_parse_init(&p, pc->p->pipe.tokens);
while (!tgsi_parse_end_of_tokens(&p)) {
const union tgsi_full_token *tok = &p.FullToken;
tgsi_parse_token(&p);
switch (tok->Token.Type) {
case TGSI_TOKEN_TYPE_IMMEDIATE:
{
const struct tgsi_full_immediate *imm =
&p.FullToken.FullImmediate;
pc->immd_nr++;
pc->immd_buf = realloc(pc->immd_buf, 4 * pc->immd_nr *
sizeof(float));
pc->immd_buf[4 * (pc->immd_nr - 1) + 0] =
imm->u.ImmediateFloat32[0].Float;
pc->immd_buf[4 * (pc->immd_nr - 1) + 1] =
imm->u.ImmediateFloat32[1].Float;
pc->immd_buf[4 * (pc->immd_nr - 1) + 2] =
imm->u.ImmediateFloat32[2].Float;
pc->immd_buf[4 * (pc->immd_nr - 1) + 3] =
imm->u.ImmediateFloat32[3].Float;
}
break;
case TGSI_TOKEN_TYPE_DECLARATION:
{
const struct tgsi_full_declaration *d;
unsigned last;
d = &p.FullToken.FullDeclaration;
last = d->u.DeclarationRange.Last;
switch (d->Declaration.File) {
case TGSI_FILE_TEMPORARY:
if (pc->temp_nr < (last + 1))
pc->temp_nr = last + 1;
break;
case TGSI_FILE_OUTPUT:
if (pc->result_nr < (last + 1))
pc->result_nr = last + 1;
break;
case TGSI_FILE_INPUT:
if (pc->attr_nr < (last + 1))
pc->attr_nr = last + 1;
break;
case TGSI_FILE_CONSTANT:
if (pc->param_nr < (last + 1))
pc->param_nr = last + 1;
break;
default:
NOUVEAU_ERR("bad decl file %d\n",
d->Declaration.File);
goto out_err;
}
}
break;
case TGSI_TOKEN_TYPE_INSTRUCTION:
break;
default:
break;
}
}
NOUVEAU_ERR("%d temps\n", pc->temp_nr);
if (pc->temp_nr) {
pc->temp = calloc(pc->temp_nr * 4, sizeof(struct nv50_reg));
if (!pc->temp)
goto out_err;
for (i = 0; i < pc->temp_nr; i++) {
for (c = 0; c < 4; c++) {
pc->temp[i*4+c].type = P_TEMP;
pc->temp[i*4+c].hw = -1;
pc->temp[i*4+c].index = i;
}
}
}
NOUVEAU_ERR("%d attrib regs\n", pc->attr_nr);
if (pc->attr_nr) {
int aid = 0;
pc->attr = calloc(pc->attr_nr * 4, sizeof(struct nv50_reg));
if (!pc->attr)
goto out_err;
for (i = 0; i < pc->attr_nr; i++) {
for (c = 0; c < 4; c++) {
pc->p->cfg.vp.attr[aid/32] |= (1 << (aid % 32));
pc->attr[i*4+c].type = P_ATTR;
pc->attr[i*4+c].hw = aid++;
pc->attr[i*4+c].index = i;
}
}
}
NOUVEAU_ERR("%d result regs\n", pc->result_nr);
if (pc->result_nr) {
int rid = 0;
pc->result = calloc(pc->result_nr * 4, sizeof(struct nv50_reg));
if (!pc->result)
goto out_err;
for (i = 0; i < pc->result_nr; i++) {
for (c = 0; c < 4; c++) {
pc->result[i*4+c].type = P_RESULT;
pc->result[i*4+c].hw = rid++;
pc->result[i*4+c].index = i;
}
}
}
NOUVEAU_ERR("%d param regs\n", pc->param_nr);
if (pc->param_nr) {
int rid = 0;
pc->param = calloc(pc->param_nr * 4, sizeof(struct nv50_reg));
if (!pc->param)
goto out_err;
for (i = 0; i < pc->param_nr; i++) {
for (c = 0; c < 4; c++) {
pc->param[i*4+c].type = P_CONST;
pc->param[i*4+c].hw = rid++;
pc->param[i*4+c].index = i;
}
}
}
if (pc->immd_nr) {
int rid = pc->param_nr * 4;
pc->immd = calloc(pc->immd_nr * 4, sizeof(struct nv50_reg));
if (!pc->immd)
goto out_err;
for (i = 0; i < pc->immd_nr; i++) {
for (c = 0; c < 4; c++) {
pc->immd[i*4+c].type = P_IMMD;
pc->immd[i*4+c].hw = rid++;
pc->immd[i*4+c].index = i;
}
}
}
ret = TRUE;
out_err:
tgsi_parse_free(&p);
return ret;
}
static boolean
nv50_program_tx(struct nv50_program *p)
{
struct tgsi_parse_context parse;
struct nv50_pc *pc;
boolean ret;
pc = CALLOC_STRUCT(nv50_pc);
if (!pc)
return FALSE;
pc->p = p;
pc->p->cfg.vp.high_temp = 4;
ret = nv50_program_tx_prep(pc);
if (ret == FALSE)
goto out_cleanup;
tgsi_parse_init(&parse, pc->p->pipe.tokens);
while (!tgsi_parse_end_of_tokens(&parse)) {
const union tgsi_full_token *tok = &parse.FullToken;
tgsi_parse_token(&parse);
switch (tok->Token.Type) {
case TGSI_TOKEN_TYPE_INSTRUCTION:
ret = nv50_program_tx_insn(pc, tok);
if (ret == FALSE)
goto out_err;
break;
default:
break;
}
}
p->param_nr = pc->param_nr * 4;
p->immd_nr = pc->immd_nr * 4;
p->immd = pc->immd_buf;
out_err:
tgsi_parse_free(&parse);
out_cleanup:
return ret;
}
static void
nv50_program_validate(struct nv50_context *nv50, struct nv50_program *p)
{
struct tgsi_parse_context pc;
tgsi_parse_init(&pc, p->pipe.tokens);
if (pc.FullHeader.Processor.Processor == TGSI_PROCESSOR_FRAGMENT) {
p->insns_nr = 8;
p->insns = malloc(p->insns_nr * sizeof(unsigned));
p->insns[0] = 0x80000000;
p->insns[1] = 0x9000000c;
p->insns[2] = 0x82010600;
p->insns[3] = 0x82020604;
p->insns[4] = 0x80030609;
p->insns[5] = 0x00020780;
p->insns[6] = 0x8004060d;
p->insns[7] = 0x00020781;
} else
if (pc.FullHeader.Processor.Processor == TGSI_PROCESSOR_VERTEX) {
int i;
if (nv50_program_tx(p) == FALSE)
assert(0);
p->insns[p->insns_nr - 1] |= 0x00000001;
for (i = 0; i < p->insns_nr; i++)
NOUVEAU_ERR("%d 0x%08x\n", i, p->insns[i]);
} else {
NOUVEAU_ERR("invalid TGSI processor\n");
tgsi_parse_free(&pc);
return;
}
tgsi_parse_free(&pc);
p->translated = TRUE;
}
void
nv50_vertprog_validate(struct nv50_context *nv50)
{
struct pipe_winsys *ws = nv50->pipe.winsys;
struct nouveau_winsys *nvws = nv50->screen->nvws;
struct nouveau_grobj *tesla = nv50->screen->tesla;
struct nv50_program *p = nv50->vertprog;
struct nouveau_stateobj *so;
void *map;
int i;
if (!p->translated) {
nv50_program_validate(nv50, p);
if (!p->translated)
assert(0);
}
if (!p->buffer)
p->buffer = ws->buffer_create(ws, 0x100, 0, p->insns_nr * 4);
map = ws->buffer_map(ws, p->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
memcpy(map, p->insns, p->insns_nr * 4);
ws->buffer_unmap(ws, p->buffer);
if (p->param_nr) {
float *cb;
cb = ws->buffer_map(ws, nv50->constbuf[PIPE_SHADER_VERTEX],
PIPE_BUFFER_USAGE_CPU_READ);
for (i = 0; i < p->param_nr; i++) {
BEGIN_RING(tesla, 0x0f00, 2);
OUT_RING (i << 8);
OUT_RING (fui(cb[i]));
}
ws->buffer_unmap(ws, nv50->constbuf[PIPE_SHADER_VERTEX]);
}
for (i = 0; i < p->immd_nr; i++) {
BEGIN_RING(tesla, 0x0f00, 2);
OUT_RING ((p->param_nr + i) << 8);
OUT_RING (fui(p->immd[i]));
}
so = so_new(11, 2);
so_method(so, tesla, NV50TCL_VP_ADDRESS_HIGH, 2);
so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
NOUVEAU_BO_HIGH, 0, 0);
so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
NOUVEAU_BO_LOW, 0, 0);
so_method(so, tesla, 0x1650, 2);
so_data (so, p->cfg.vp.attr[0]);
so_data (so, p->cfg.vp.attr[1]);
so_method(so, tesla, 0x16ac, 2);
so_data (so, 8);
so_data (so, p->cfg.vp.high_temp);
so_method(so, tesla, 0x140c, 1);
so_data (so, 0); /* program start offset */
so_emit(nv50->screen->nvws, so);
so_ref(NULL, &so);
}
void
nv50_fragprog_validate(struct nv50_context *nv50)
{
struct pipe_winsys *ws = nv50->pipe.winsys;
struct nouveau_grobj *tesla = nv50->screen->tesla;
struct nv50_program *p = nv50->fragprog;
struct nouveau_stateobj *so;
void *map;
if (!p->translated) {
nv50_program_validate(nv50, p);
if (!p->translated)
assert(0);
}
if (!p->buffer)
p->buffer = ws->buffer_create(ws, 0x100, 0, p->insns_nr * 4);
map = ws->buffer_map(ws, p->buffer, PIPE_BUFFER_USAGE_CPU_WRITE);
memcpy(map, p->insns, p->insns_nr * 4);
ws->buffer_unmap(ws, p->buffer);
so = so_new(3, 2);
so_method(so, tesla, NV50TCL_FP_ADDRESS_HIGH, 2);
so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
NOUVEAU_BO_HIGH, 0, 0);
so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
NOUVEAU_BO_LOW, 0, 0);
so_emit(nv50->screen->nvws, so);
so_ref(NULL, &so);
}
void
nv50_program_destroy(struct nv50_context *nv50, struct nv50_program *p)
{
struct pipe_winsys *ws = nv50->pipe.winsys;
if (p->insns_nr) {
if (p->insns)
FREE(p->insns);
p->insns_nr = 0;
}
if (p->buffer)
pipe_buffer_reference(ws, &p->buffer, NULL);
p->translated = 0;
}
+67 -1
View File
@@ -203,8 +203,19 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws)
return NULL;
}
/* Static constant buffer */
screen->constbuf = ws->buffer_create(ws, 0, 0, 256 * 4 * 4);
if (nvws->res_init(&screen->vp_data_heap, 0, 256)) {
NOUVEAU_ERR("Error initialising constant buffer\n");
nv50_screen_destroy(&screen->pipe);
return NULL;
}
/* Static tesla init */
so = so_new(128, 0);
so = so_new(256, 20);
so_method(so, screen->tesla, 0x1558, 1);
so_data (so, 1);
so_method(so, screen->tesla, NV50TCL_DMA_NOTIFY, 1);
so_data (so, screen->sync->handle);
so_method(so, screen->tesla, NV50TCL_DMA_IN_MEMORY0(0),
@@ -215,6 +226,61 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_winsys *nvws)
NV50TCL_DMA_IN_MEMORY1__SIZE);
for (i = 0; i < NV50TCL_DMA_IN_MEMORY1__SIZE; i++)
so_data(so, nvws->channel->vram->handle);
so_method(so, screen->tesla, 0x121c, 1);
so_data (so, 1);
so_method(so, screen->tesla, 0x13bc, 1);
so_data (so, 0x54);
so_method(so, screen->tesla, 0x13ac, 1);
so_data (so, 1);
so_method(so, screen->tesla, 0x16bc, 2);
so_data (so, 0x03020100);
so_data (so, 0x07060504);
so_method(so, screen->tesla, 0x1988, 2);
so_data (so, 0x08040404);
so_data (so, 0x00000004);
so_method(so, screen->tesla, 0x16ac, 2);
so_data (so, 8);
so_data (so, 4);
so_method(so, screen->tesla, 0x16b8, 1);
so_data (so, 8);
so_method(so, screen->tesla, 0x1280, 3);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
so_data (so, 0x00001000);
so_method(so, screen->tesla, 0x1280, 3);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
so_data (so, 0x00014000);
so_method(so, screen->tesla, 0x1280, 3);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
so_data (so, 0x00024000);
so_method(so, screen->tesla, 0x1280, 3);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
so_data (so, 0x00034000);
so_method(so, screen->tesla, 0x1280, 3);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
so_reloc (so, screen->constbuf, 0, NOUVEAU_BO_VRAM |
NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
so_data (so, 0x00040100);
for (i = 0; i < 16; i++) {
so_method(so, screen->tesla, 0x1080 + (i * 8), 2);
so_data (so, 0x000000ff);
so_data (so, 0xffffffff);
}
so_emit(nvws, so);
so_ref(NULL, &so);
+3
View File
@@ -12,6 +12,9 @@ struct nv50_screen {
struct nouveau_grobj *tesla;
struct nouveau_notifier *sync;
struct pipe_buffer *constbuf;
struct nouveau_resource *vp_data_heap;
};
static INLINE struct nv50_screen *
+50 -4
View File
@@ -248,8 +248,8 @@ nv50_depth_stencil_alpha_state_create(struct pipe_context *pipe,
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_data (so, 0); //cso->depth.writemask ? 1 : 0);
if (0 && 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);
@@ -328,34 +328,58 @@ static void *
nv50_vp_state_create(struct pipe_context *pipe,
const struct pipe_shader_state *cso)
{
return NULL;
struct nv50_program *p = CALLOC_STRUCT(nv50_program);
p->pipe = *cso;
tgsi_scan_shader(p->pipe.tokens, &p->info);
return (void *)p;
}
static void
nv50_vp_state_bind(struct pipe_context *pipe, void *hwcso)
{
struct nv50_context *nv50 = nv50_context(pipe);
nv50->vertprog = hwcso;
nv50->dirty |= NV50_NEW_VERTPROG;
}
static void
nv50_vp_state_delete(struct pipe_context *pipe, void *hwcso)
{
struct nv50_context *nv50 = nv50_context(pipe);
nv50_program_destroy(nv50, hwcso);
FREE(hwcso);
}
static void *
nv50_fp_state_create(struct pipe_context *pipe,
const struct pipe_shader_state *cso)
{
return NULL;
struct nv50_program *p = CALLOC_STRUCT(nv50_program);
p->pipe = *cso;
tgsi_scan_shader(p->pipe.tokens, &p->info);
return (void *)p;
}
static void
nv50_fp_state_bind(struct pipe_context *pipe, void *hwcso)
{
struct nv50_context *nv50 = nv50_context(pipe);
nv50->fragprog = hwcso;
nv50->dirty |= NV50_NEW_FRAGPROG;
}
static void
nv50_fp_state_delete(struct pipe_context *pipe, void *hwcso)
{
struct nv50_context *nv50 = nv50_context(pipe);
nv50_program_destroy(nv50, hwcso);
FREE(hwcso);
}
static void
@@ -378,6 +402,16 @@ static void
nv50_set_constant_buffer(struct pipe_context *pipe, uint shader, uint index,
const struct pipe_constant_buffer *buf )
{
struct nv50_context *nv50 = nv50_context(pipe);
if (shader == PIPE_SHADER_VERTEX) {
nv50->constbuf[PIPE_SHADER_VERTEX] = buf->buffer;
nv50->dirty |= NV50_NEW_VERTPROG;
} else
if (shader == PIPE_SHADER_FRAGMENT) {
nv50->constbuf[PIPE_SHADER_FRAGMENT] = buf->buffer;
nv50->dirty |= NV50_NEW_FRAGPROG;
}
}
static void
@@ -424,12 +458,24 @@ static void
nv50_set_vertex_buffers(struct pipe_context *pipe, unsigned count,
const struct pipe_vertex_buffer *vb)
{
struct nv50_context *nv50 = nv50_context(pipe);
memcpy(nv50->vtxbuf, vb, sizeof(*vb) * count);
nv50->vtxbuf_nr = count;
nv50->dirty |= NV50_NEW_ARRAYS;
}
static void
nv50_set_vertex_elements(struct pipe_context *pipe, unsigned count,
const struct pipe_vertex_element *ve)
{
struct nv50_context *nv50 = nv50_context(pipe);
memcpy(nv50->vtxelt, ve, sizeof(*ve) * count);
nv50->vtxelt_nr = count;
nv50->dirty |= NV50_NEW_ARRAYS;
}
void
+30
View File
@@ -2,6 +2,36 @@
#define __NV50_STATE_H__
#include "pipe/p_state.h"
#include "tgsi/util/tgsi_scan.h"
struct nv50_program_data {
int index;
int component;
float value;
};
struct nv50_program {
struct pipe_shader_state pipe;
struct tgsi_shader_info info;
boolean translated;
unsigned *insns;
unsigned insns_nr;
struct pipe_buffer *buffer;
unsigned param_nr;
float *immd;
unsigned immd_nr;
struct nouveau_resource *data;
union {
struct {
unsigned high_temp;
unsigned attr[2];
} vp;
} cfg;
};
#endif
+22 -7
View File
@@ -15,8 +15,8 @@ nv50_state_validate_fb(struct nv50_context *nv50)
h = fb->cbufs[i]->height;
gw = 1;
} else {
assert(w != fb->cbufs[i]->width);
assert(h != fb->cbufs[i]->height);
assert(w == fb->cbufs[i]->width);
assert(h == fb->cbufs[i]->height);
}
so_method(so, tesla, NV50TCL_RT_HORIZ(i), 2);
@@ -46,6 +46,9 @@ nv50_state_validate_fb(struct nv50_context *nv50)
}
so_data(so, 0x00000040);
so_data(so, 0x00000000);
so_method(so, tesla, 0x1224, 1);
so_data (so, 1);
}
if (fb->zsbuf) {
@@ -54,11 +57,11 @@ nv50_state_validate_fb(struct nv50_context *nv50)
h = fb->zsbuf->height;
gw = 1;
} else {
assert(w != fb->zsbuf->width);
assert(h != fb->zsbuf->height);
assert(w == fb->zsbuf->width);
assert(h == fb->zsbuf->height);
}
so_method(so, tesla, NV50TCL_RT_ADDRESS_HIGH(i), 5);
so_method(so, tesla, NV50TCL_ZETA_ADDRESS_HIGH, 5);
so_reloc (so, fb->zsbuf->buffer, fb->zsbuf->offset,
NOUVEAU_BO_VRAM | NOUVEAU_BO_HIGH, 0, 0);
so_reloc (so, fb->zsbuf->buffer, fb->zsbuf->offset,
@@ -83,9 +86,12 @@ nv50_state_validate_fb(struct nv50_context *nv50)
so_method(so, tesla, NV50TCL_VIEWPORT_HORIZ, 2);
so_data (so, w << 16);
so_data (so, h << 16);
so_method(so, tesla, 0xff0, 2);
so_method(so, tesla, 0xff4, 2);
so_data (so, w << 16);
so_data (so, h << 16);
so_method(so, tesla, 0xdf8, 2);
so_data (so, 0);
so_data (so, h);
so_emit(nv50->screen->nvws, so);
so_ref(NULL, &so);
@@ -108,6 +114,12 @@ nv50_state_validate(struct nv50_context *nv50)
if (nv50->dirty & NV50_NEW_ZSA)
so_emit(nvws, nv50->zsa->so);
if (nv50->dirty & NV50_NEW_VERTPROG)
nv50_vertprog_validate(nv50);
if (nv50->dirty & NV50_NEW_FRAGPROG)
nv50_fragprog_validate(nv50);
if (nv50->dirty & NV50_NEW_RASTERIZER)
so_emit(nvws, nv50->rasterizer->so);
@@ -150,12 +162,15 @@ nv50_state_validate(struct nv50_context *nv50)
so_data (so, fui(nv50->viewport.translate[2]));
so_method(so, tesla, NV50TCL_VIEWPORT_UNK1(0), 3);
so_data (so, fui(nv50->viewport.scale[0]));
so_data (so, fui(nv50->viewport.scale[1]));
so_data (so, fui(-nv50->viewport.scale[1]));
so_data (so, fui(nv50->viewport.scale[2]));
so_emit(nvws, so);
so_ref(NULL, &so);
}
if (nv50->dirty & NV50_NEW_ARRAYS)
nv50_vbo_validate(nv50);
nv50->dirty = 0;
return TRUE;
}
+84 -1
View File
@@ -5,6 +5,29 @@
#include "nv50_context.h"
#include "nv50_state.h"
static INLINE unsigned
nv50_prim(unsigned mode)
{
switch (mode) {
case PIPE_PRIM_POINTS: return NV50TCL_VERTEX_BEGIN_POINTS;
case PIPE_PRIM_LINES: return NV50TCL_VERTEX_BEGIN_LINES;
case PIPE_PRIM_LINE_LOOP: return NV50TCL_VERTEX_BEGIN_LINE_LOOP;
case PIPE_PRIM_LINE_STRIP: return NV50TCL_VERTEX_BEGIN_LINE_STRIP;
case PIPE_PRIM_TRIANGLES: return NV50TCL_VERTEX_BEGIN_TRIANGLES;
case PIPE_PRIM_TRIANGLE_STRIP:
return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP;
case PIPE_PRIM_TRIANGLE_FAN: return NV50TCL_VERTEX_BEGIN_TRIANGLE_FAN;
case PIPE_PRIM_QUADS: return NV50TCL_VERTEX_BEGIN_QUADS;
case PIPE_PRIM_QUAD_STRIP: return NV50TCL_VERTEX_BEGIN_QUAD_STRIP;
case PIPE_PRIM_POLYGON: return NV50TCL_VERTEX_BEGIN_POLYGON;
default:
break;
}
NOUVEAU_ERR("invalid primitive type %d\n", mode);
return NV50TCL_VERTEX_BEGIN_POINTS;
}
boolean
nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
unsigned count)
@@ -12,8 +35,22 @@ nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
struct nv50_context *nv50 = nv50_context(pipe);
nv50_state_validate(nv50);
NOUVEAU_ERR("unimplemented\n");
BEGIN_RING(tesla, 0x142c, 1);
OUT_RING (0);
BEGIN_RING(tesla, 0x142c, 1);
OUT_RING (0);
BEGIN_RING(tesla, NV50TCL_VERTEX_BEGIN, 1);
OUT_RING (nv50_prim(mode));
BEGIN_RING(tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2);
OUT_RING (start);
OUT_RING (count);
BEGIN_RING(tesla, NV50TCL_VERTEX_END, 1);
OUT_RING (0);
pipe->flush(pipe, 0, NULL);
return TRUE;
}
@@ -30,3 +67,49 @@ nv50_draw_elements(struct pipe_context *pipe,
return TRUE;
}
void
nv50_vbo_validate(struct nv50_context *nv50)
{
struct nouveau_grobj *tesla = nv50->screen->tesla;
struct nouveau_stateobj *vtxbuf, *vtxfmt;
int i, vpi = 0;
vtxbuf = so_new(nv50->vtxelt_nr * 4, nv50->vtxelt_nr * 2);
vtxfmt = so_new(nv50->vtxelt_nr + 1, 0);
so_method(vtxfmt, tesla, 0x1ac0, nv50->vtxelt_nr);
for (i = 0; i < nv50->vtxelt_nr; i++) {
struct pipe_vertex_element *ve = &nv50->vtxelt[i];
struct pipe_vertex_buffer *vb =
&nv50->vtxbuf[ve->vertex_buffer_index];
switch (ve->src_format) {
case PIPE_FORMAT_R32G32B32_FLOAT:
so_data(vtxfmt, 0x7e100000 | i);
break;
default:
{
char fmt[128];
pf_sprint_name(fmt, ve->src_format);
NOUVEAU_ERR("invalid vbo format %s\n", fmt);
assert(0);
return;
}
}
so_method(vtxbuf, tesla, 0x900 + (i * 16), 3);
so_data (vtxbuf, 0x20000000 | vb->pitch);
so_reloc (vtxbuf, vb->buffer, vb->buffer_offset +
ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
NOUVEAU_BO_HIGH, 0, 0);
so_reloc (vtxbuf, vb->buffer, vb->buffer_offset +
ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD |
NOUVEAU_BO_LOW, 0, 0);
}
so_emit(nv50->screen->nvws, vtxfmt);
so_ref (NULL, &vtxfmt);
so_emit(nv50->screen->nvws, vtxbuf);
so_ref (NULL, &vtxbuf);
}