nv50_program.c revision 22e0acc466947b203574c88f4964f61ef46ae3fd
1#include "pipe/p_context.h" 2#include "pipe/p_defines.h" 3#include "pipe/p_state.h" 4#include "pipe/p_inlines.h" 5 6#include "pipe/p_shader_tokens.h" 7#include "tgsi/util/tgsi_parse.h" 8#include "tgsi/util/tgsi_util.h" 9 10#include "nv50_context.h" 11#include "nv50_state.h" 12 13#define OP_MOV 0x001 14#define OP_INTERP 0x008 15#define OP_RCP 0x009 16#define OP_ADD 0x00b 17#define OP_MUL 0x00c 18#define OP_MAD 0x00e 19#define NV50_SU_MAX_TEMP 64 20 21struct nv50_reg { 22 enum { 23 P_TEMP, 24 P_ATTR, 25 P_RESULT, 26 P_CONST, 27 P_IMMD 28 } type; 29 int index; 30 31 int hw; 32 int neg; 33}; 34 35struct nv50_pc { 36 struct nv50_program *p; 37 38 /* hw resources */ 39 struct nv50_reg *r_temp[NV50_SU_MAX_TEMP]; 40 41 /* tgsi resources */ 42 struct nv50_reg *temp; 43 int temp_nr; 44 struct nv50_reg *attr; 45 int attr_nr; 46 struct nv50_reg *result; 47 int result_nr; 48 struct nv50_reg *param; 49 int param_nr; 50 struct nv50_reg *immd; 51 float *immd_buf; 52 int immd_nr; 53}; 54 55static void 56alloc_reg(struct nv50_pc *pc, struct nv50_reg *reg) 57{ 58 int i; 59 60 if (reg->type != P_TEMP || reg->hw >= 0) 61 return; 62 63 for (i = 0; i < NV50_SU_MAX_TEMP; i++) { 64 if (!(pc->r_temp[i])) { 65 pc->r_temp[i] = reg; 66 reg->hw = i; 67 if (pc->p->cfg.vp.high_temp < (i + 1)) 68 pc->p->cfg.vp.high_temp = i + 1; 69 return; 70 } 71 } 72 73 assert(0); 74} 75 76static struct nv50_reg * 77alloc_temp(struct nv50_pc *pc, struct nv50_reg *dst) 78{ 79 struct nv50_reg *r; 80 int i; 81 82 if (dst && dst->type == P_TEMP && dst->hw == -1) 83 return dst; 84 85 for (i = 0; i < NV50_SU_MAX_TEMP; i++) { 86 if (!pc->r_temp[i]) { 87 r = CALLOC_STRUCT(nv50_reg); 88 r->type = P_TEMP; 89 r->index = -1; 90 r->hw = i; 91 pc->r_temp[i] = r; 92 return r; 93 } 94 } 95 96 assert(0); 97 return NULL; 98} 99 100static void 101free_temp(struct nv50_pc *pc, struct nv50_reg *r) 102{ 103 if (r->index == -1) { 104 FREE(pc->r_temp[r->hw]); 105 pc->r_temp[r->hw] = NULL; 106 } 107} 108 109#if 0 110static struct nv50_reg * 111constant(struct nv50_pc *pc, int pipe, int c, float v) 112{ 113 struct nv50_reg *r = CALLOC_STRUCT(nv50_reg); 114 struct nv50_program *p = pc->p; 115 struct nv50_program_data *pd; 116 int idx; 117 118 if (pipe >= 0) { 119 for (idx = 0; idx < p->nr_consts; idx++) { 120 if (p->consts[idx].index == pipe) 121 return nv40_sr(NV40SR_CONST, idx); 122 } 123 } 124 125 idx = p->nr_consts++; 126 p->consts = realloc(p->consts, sizeof(*pd) * p->nr_consts); 127 pd = &p->consts[idx]; 128 129 pd->index = pipe; 130 pd->component = c; 131 pd->value = v; 132 return nv40_sr(NV40SR_CONST, idx); 133} 134#endif 135 136static void 137emit(struct nv50_pc *pc, unsigned op, struct nv50_reg *dst, 138 struct nv50_reg *src0, struct nv50_reg *src1, struct nv50_reg *src2) 139{ 140 struct nv50_program *p = pc->p; 141 struct nv50_reg *tmp0 = NULL, *tmp = NULL, *tmp2 = NULL; 142 unsigned inst[2] = { 0, 0 }; 143 144 /* Grr.. Fun restrictions on where attribs can be sourced from.. */ 145 if (src0 && (src0->type == P_CONST || src0->type == P_IMMD) && 146 (op == OP_MUL || op == OP_MAD)) { 147 tmp = src1; 148 src1 = src0; 149 src0 = tmp; 150 tmp = NULL; 151 } 152 153 if (src1 && src1->type == P_ATTR) { 154 tmp = alloc_temp(pc, dst); 155 tmp->neg = src1->neg; src1->neg = 0; 156 emit(pc, 1, tmp, src1, NULL, NULL); 157 src1 = tmp; 158 } 159 160 if (src2 && src2->type == P_ATTR) { 161 tmp2 = alloc_temp(pc, dst); 162 tmp2->neg = src2->neg; src2->neg = 0; 163 emit(pc, 1, tmp2, src2, NULL, NULL); 164 src2 = tmp2; 165 } 166 167 /* Get this out of the way first. What type of opcode do we 168 * want/need to build? 169 */ 170 if ((op & 0x3f0) || dst->type == P_RESULT || 171 (src0 && src0->type == P_ATTR) || src1 || src2) 172 inst[0] |= 0x00000001; 173 174 if (inst[0] & 0x00000001) { 175 inst[0] |= ((op & 0xf) << 28); 176 inst[1] |= ((op >> 4) << 26); 177 178 alloc_reg(pc, dst); 179 if (dst->type == P_RESULT) 180 inst[1] |= 0x00000008; 181 inst[0] |= (dst->hw << 2); 182 183 if (src0) { 184 if (src0->type == P_ATTR) 185 inst[1] |= 0x00200000; 186 else 187 if (src0->type == P_CONST || src0->type == P_IMMD) 188 assert(0); 189 alloc_reg(pc, src0); 190 inst[0] |= (src0->hw << 9); 191 } 192 193 if (src1) { 194 if (src1->type == P_CONST || src1->type == P_IMMD) { 195 if (src1->type == P_IMMD) 196 inst[1] |= (NV50_CB_PMISC << 22); 197 else 198 inst[1] |= (NV50_CB_PVP << 22); 199 inst[0] |= 0x00800000; /* src1 is const */ 200 /*XXX: does src1 come from "src2" now? */ 201 alloc_reg(pc, src1); 202 inst[0] |= (src1->hw << 16); 203 } else { 204 alloc_reg(pc, src1); 205 if (op == OP_MUL || op == OP_MAD) 206 inst[0] |= (src1->hw << 16); 207 else 208 inst[1] |= (src1->hw << 14); 209 } 210 } else { 211 inst[1] |= 0x0003c000; /*XXX FIXME */ 212 } 213 214 if (src2) { 215 if (src2->type == P_CONST || src2->type == P_IMMD) { 216 if (src2->type == P_IMMD) 217 inst[1] |= (NV50_CB_PMISC << 22); 218 else 219 inst[1] |= (NV50_CB_PVP << 22); 220 inst[0] |= 0x01000000; /* src2 is const */ 221 inst[1] |= (src2->hw << 14); 222 } else { 223 alloc_reg(pc, src2); 224 if (inst[0] & 0x00800000 || op == OP_MAD) 225 inst[1] |= (src2->hw << 14); 226 else 227 inst[0] |= (src2->hw << 16); 228 } 229 } 230 231 /*XXX: FIXME */ 232 switch (op) { 233 case OP_ADD: 234 case OP_MUL: 235 case OP_RCP: 236 case OP_MAD: 237 /* 0x04000000 negates arg0 */ 238 /* 0x08000000 negates arg1 */ 239 /*XXX: true for !0xb also ? */ 240 if (src0 && src0->neg) 241 inst[1] |= 0x04000000; 242 if (src1 && src1->neg) 243 inst[1] |= 0x08000000; 244 inst[1] |= 0x00000780; 245 break; 246 default: 247 /* 0x04000000 == arg0 32 bit, otherwise 16 bit */ 248 inst[1] |= 0x04000780; 249 break; 250 } 251 } else { 252 inst[0] |= ((op & 0xf) << 28); 253 254 alloc_reg(pc, dst); 255 inst[0] |= (dst->hw << 2); 256 257 if (src0) { 258 alloc_reg(pc, src0); 259 inst[0] |= (src0->hw << 9); 260 } 261 262 /*XXX: NFI if this even works - probably not.. */ 263 if (src1) { 264 alloc_reg(pc, src1); 265 inst[0] |= (src1->hw << 16); 266 } 267 } 268 269 if (tmp0) free_temp(pc, tmp0); 270 if (tmp) free_temp(pc, tmp); 271 if (tmp2) free_temp(pc, tmp2); 272 273 if (inst[0] & 1) { 274 p->insns_nr += 2; 275 p->insns = realloc(p->insns, sizeof(unsigned) * p->insns_nr); 276 memcpy(p->insns + (p->insns_nr - 2), inst, sizeof(unsigned)*2); 277 } else { 278 p->insns_nr += 1; 279 p->insns = realloc(p->insns, sizeof(unsigned) * p->insns_nr); 280 memcpy(p->insns + (p->insns_nr - 1), inst, sizeof(unsigned)); 281 } 282} 283 284static struct nv50_reg * 285tgsi_dst(struct nv50_pc *pc, int c, const struct tgsi_full_dst_register *dst) 286{ 287 switch (dst->DstRegister.File) { 288 case TGSI_FILE_TEMPORARY: 289 return &pc->temp[dst->DstRegister.Index * 4 + c]; 290 case TGSI_FILE_OUTPUT: 291 return &pc->result[dst->DstRegister.Index * 4 + c]; 292 case TGSI_FILE_NULL: 293 return NULL; 294 default: 295 break; 296 } 297 298 return NULL; 299} 300 301static struct nv50_reg * 302tgsi_src(struct nv50_pc *pc, int c, const struct tgsi_full_src_register *src) 303{ 304 /* Handle swizzling */ 305 switch (c) { 306 case 0: c = src->SrcRegister.SwizzleX; break; 307 case 1: c = src->SrcRegister.SwizzleY; break; 308 case 2: c = src->SrcRegister.SwizzleZ; break; 309 case 3: c = src->SrcRegister.SwizzleW; break; 310 default: 311 assert(0); 312 } 313 314 switch (src->SrcRegister.File) { 315 case TGSI_FILE_INPUT: 316 return &pc->attr[src->SrcRegister.Index * 4 + c]; 317 case TGSI_FILE_TEMPORARY: 318 return &pc->temp[src->SrcRegister.Index * 4 + c]; 319 case TGSI_FILE_CONSTANT: 320 return &pc->param[src->SrcRegister.Index * 4 + c]; 321 case TGSI_FILE_IMMEDIATE: 322 return &pc->immd[src->SrcRegister.Index * 4 + c]; 323 default: 324 break; 325 } 326 327 return NULL; 328} 329 330static boolean 331nv50_program_tx_insn(struct nv50_pc *pc, const union tgsi_full_token *tok) 332{ 333 const struct tgsi_full_instruction *inst = &tok->FullInstruction; 334 struct nv50_reg *dst[4], *src[3][4], *none = NULL, *tmp; 335 unsigned mask; 336 int i, c; 337 338 NOUVEAU_ERR("insn %p\n", tok); 339 340 mask = inst->FullDstRegisters[0].DstRegister.WriteMask; 341 342 for (c = 0; c < 4; c++) { 343 if (mask & (1 << c)) 344 dst[c] = tgsi_dst(pc, c, &inst->FullDstRegisters[0]); 345 else 346 dst[c] = NULL; 347 } 348 349 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { 350 for (c = 0; c < 4; c++) 351 src[i][c] = tgsi_src(pc, c, &inst->FullSrcRegisters[i]); 352 } 353 354 switch (inst->Instruction.Opcode) { 355 case TGSI_OPCODE_ADD: 356 for (c = 0; c < 4; c++) { 357 if (mask & (1 << c)) { 358 emit(pc, OP_ADD, dst[c], 359 src[0][c], src[1][c], none); 360 } 361 } 362 break; 363 case TGSI_OPCODE_DP3: 364 tmp = alloc_temp(pc, NULL); 365 emit(pc, OP_MUL, tmp, src[0][0], src[1][0], NULL); 366 emit(pc, OP_MAD, tmp, src[0][1], src[1][1], tmp); 367 emit(pc, OP_MAD, tmp, src[0][2], src[1][2], tmp); 368 for (c = 0; c < 4; c++) { 369 if (mask & (1 << c)) 370 emit(pc, OP_MOV, dst[c], tmp, none, none); 371 } 372 free_temp(pc, tmp); 373 break; 374 case TGSI_OPCODE_DP4: 375 tmp = alloc_temp(pc, NULL); 376 emit(pc, OP_MUL, tmp, src[0][0], src[1][0], NULL); 377 emit(pc, OP_MAD, tmp, src[0][1], src[1][1], tmp); 378 emit(pc, OP_MAD, tmp, src[0][2], src[1][2], tmp); 379 emit(pc, OP_MAD, tmp, src[0][3], src[1][3], tmp); 380 for (c = 0; c < 4; c++) { 381 if (mask & (1 << c)) 382 emit(pc, OP_MOV, dst[c], tmp, none, none); 383 } 384 free_temp(pc, tmp); 385 break; 386 case TGSI_OPCODE_DPH: 387 tmp = alloc_temp(pc, NULL); 388 emit(pc, OP_MUL, tmp, src[0][0], src[1][0], NULL); 389 emit(pc, OP_MAD, tmp, src[0][1], src[1][1], tmp); 390 emit(pc, OP_MAD, tmp, src[0][2], src[1][2], tmp); 391 emit(pc, OP_ADD, tmp, src[1][3], tmp, NULL); 392 for (c = 0; c < 4; c++) { 393 if (mask & (1 << c)) 394 emit(pc, OP_MOV, dst[c], tmp, none, none); 395 } 396 free_temp(pc, tmp); 397 break; 398 case TGSI_OPCODE_MAD: 399 for (c = 0; c < 4; c++) { 400 if (mask & (1 << c)) 401 emit(pc, OP_MAD, dst[c], 402 src[0][c], src[1][c], src[2][c]); 403 } 404 break; 405 case TGSI_OPCODE_MOV: 406 for (c = 0; c < 4; c++) { 407 if (mask & (1 << c)) 408 emit(pc, OP_MOV, dst[c], src[0][c], none, none); 409 } 410 break; 411 case TGSI_OPCODE_MUL: 412 for (c = 0; c < 4; c++) { 413 if (mask & (1 << c)) 414 emit(pc, OP_MUL, dst[c], 415 src[0][c], src[1][c], none); 416 } 417 break; 418 case TGSI_OPCODE_RCP: 419 for (c = 0; c < 4; c++) { 420 if (mask & (1 << c)) 421 emit(pc, OP_RCP, dst[c], 422 src[0][c], none, none); 423 } 424 break; 425 case TGSI_OPCODE_SUB: 426 for (c = 0; c < 4; c++) { 427 if (mask & (1 << c)) { 428 src[1][c]->neg = 1; 429 emit(pc, OP_ADD, dst[c], 430 src[0][c], src[1][c], none); 431 src[1][c]->neg = 0; 432 } 433 } 434 break; 435 case TGSI_OPCODE_END: 436 break; 437 default: 438 NOUVEAU_ERR("invalid opcode %d\n", inst->Instruction.Opcode); 439 return FALSE; 440 } 441 442 return TRUE; 443} 444 445static boolean 446nv50_program_tx_prep(struct nv50_pc *pc) 447{ 448 struct tgsi_parse_context p; 449 boolean ret = FALSE; 450 unsigned i, c; 451 452 tgsi_parse_init(&p, pc->p->pipe.tokens); 453 while (!tgsi_parse_end_of_tokens(&p)) { 454 const union tgsi_full_token *tok = &p.FullToken; 455 456 tgsi_parse_token(&p); 457 switch (tok->Token.Type) { 458 case TGSI_TOKEN_TYPE_IMMEDIATE: 459 { 460 const struct tgsi_full_immediate *imm = 461 &p.FullToken.FullImmediate; 462 463 pc->immd_nr++; 464 pc->immd_buf = realloc(pc->immd_buf, 4 * pc->immd_nr * 465 sizeof(float)); 466 pc->immd_buf[4 * (pc->immd_nr - 1) + 0] = 467 imm->u.ImmediateFloat32[0].Float; 468 pc->immd_buf[4 * (pc->immd_nr - 1) + 1] = 469 imm->u.ImmediateFloat32[1].Float; 470 pc->immd_buf[4 * (pc->immd_nr - 1) + 2] = 471 imm->u.ImmediateFloat32[2].Float; 472 pc->immd_buf[4 * (pc->immd_nr - 1) + 3] = 473 imm->u.ImmediateFloat32[3].Float; 474 } 475 break; 476 case TGSI_TOKEN_TYPE_DECLARATION: 477 { 478 const struct tgsi_full_declaration *d; 479 unsigned last; 480 481 d = &p.FullToken.FullDeclaration; 482 last = d->u.DeclarationRange.Last; 483 484 switch (d->Declaration.File) { 485 case TGSI_FILE_TEMPORARY: 486 if (pc->temp_nr < (last + 1)) 487 pc->temp_nr = last + 1; 488 break; 489 case TGSI_FILE_OUTPUT: 490 if (pc->result_nr < (last + 1)) 491 pc->result_nr = last + 1; 492 break; 493 case TGSI_FILE_INPUT: 494 if (pc->attr_nr < (last + 1)) 495 pc->attr_nr = last + 1; 496 break; 497 case TGSI_FILE_CONSTANT: 498 if (pc->param_nr < (last + 1)) 499 pc->param_nr = last + 1; 500 break; 501 default: 502 NOUVEAU_ERR("bad decl file %d\n", 503 d->Declaration.File); 504 goto out_err; 505 } 506 } 507 break; 508 case TGSI_TOKEN_TYPE_INSTRUCTION: 509 break; 510 default: 511 break; 512 } 513 } 514 515 NOUVEAU_ERR("%d temps\n", pc->temp_nr); 516 if (pc->temp_nr) { 517 pc->temp = calloc(pc->temp_nr * 4, sizeof(struct nv50_reg)); 518 if (!pc->temp) 519 goto out_err; 520 521 for (i = 0; i < pc->temp_nr; i++) { 522 for (c = 0; c < 4; c++) { 523 pc->temp[i*4+c].type = P_TEMP; 524 pc->temp[i*4+c].hw = -1; 525 pc->temp[i*4+c].index = i; 526 } 527 } 528 } 529 530 NOUVEAU_ERR("%d attrib regs\n", pc->attr_nr); 531 if (pc->attr_nr) { 532 int aid = 0; 533 534 pc->attr = calloc(pc->attr_nr * 4, sizeof(struct nv50_reg)); 535 if (!pc->attr) 536 goto out_err; 537 538 for (i = 0; i < pc->attr_nr; i++) { 539 for (c = 0; c < 4; c++) { 540 pc->p->cfg.vp.attr[aid/32] |= (1 << (aid % 32)); 541 pc->attr[i*4+c].type = P_ATTR; 542 pc->attr[i*4+c].hw = aid++; 543 pc->attr[i*4+c].index = i; 544 } 545 } 546 } 547 548 NOUVEAU_ERR("%d result regs\n", pc->result_nr); 549 if (pc->result_nr) { 550 int rid = 0; 551 552 pc->result = calloc(pc->result_nr * 4, sizeof(struct nv50_reg)); 553 if (!pc->result) 554 goto out_err; 555 556 for (i = 0; i < pc->result_nr; i++) { 557 for (c = 0; c < 4; c++) { 558 pc->result[i*4+c].type = P_RESULT; 559 pc->result[i*4+c].hw = rid++; 560 pc->result[i*4+c].index = i; 561 } 562 } 563 } 564 565 NOUVEAU_ERR("%d param regs\n", pc->param_nr); 566 if (pc->param_nr) { 567 int rid = 0; 568 569 pc->param = calloc(pc->param_nr * 4, sizeof(struct nv50_reg)); 570 if (!pc->param) 571 goto out_err; 572 573 for (i = 0; i < pc->param_nr; i++) { 574 for (c = 0; c < 4; c++) { 575 pc->param[i*4+c].type = P_CONST; 576 pc->param[i*4+c].hw = rid++; 577 pc->param[i*4+c].index = i; 578 } 579 } 580 } 581 582 if (pc->immd_nr) { 583 int rid = 0; 584 585 pc->immd = calloc(pc->immd_nr * 4, sizeof(struct nv50_reg)); 586 if (!pc->immd) 587 goto out_err; 588 589 for (i = 0; i < pc->immd_nr; i++) { 590 for (c = 0; c < 4; c++) { 591 pc->immd[i*4+c].type = P_IMMD; 592 pc->immd[i*4+c].hw = rid++; 593 pc->immd[i*4+c].index = i; 594 } 595 } 596 } 597 598 ret = TRUE; 599out_err: 600 tgsi_parse_free(&p); 601 return ret; 602} 603 604static boolean 605nv50_program_tx(struct nv50_program *p) 606{ 607 struct tgsi_parse_context parse; 608 struct nv50_pc *pc; 609 boolean ret; 610 611 pc = CALLOC_STRUCT(nv50_pc); 612 if (!pc) 613 return FALSE; 614 pc->p = p; 615 pc->p->cfg.vp.high_temp = 4; 616 617 ret = nv50_program_tx_prep(pc); 618 if (ret == FALSE) 619 goto out_cleanup; 620 621 tgsi_parse_init(&parse, pc->p->pipe.tokens); 622 while (!tgsi_parse_end_of_tokens(&parse)) { 623 const union tgsi_full_token *tok = &parse.FullToken; 624 625 tgsi_parse_token(&parse); 626 627 switch (tok->Token.Type) { 628 case TGSI_TOKEN_TYPE_INSTRUCTION: 629 ret = nv50_program_tx_insn(pc, tok); 630 if (ret == FALSE) 631 goto out_err; 632 break; 633 default: 634 break; 635 } 636 } 637 638 p->immd_nr = pc->immd_nr * 4; 639 p->immd = pc->immd_buf; 640 641out_err: 642 tgsi_parse_free(&parse); 643 644out_cleanup: 645 return ret; 646} 647 648static void 649nv50_program_validate(struct nv50_context *nv50, struct nv50_program *p) 650{ 651 struct tgsi_parse_context pc; 652 653 tgsi_parse_init(&pc, p->pipe.tokens); 654 655 if (pc.FullHeader.Processor.Processor == TGSI_PROCESSOR_FRAGMENT) { 656 p->insns_nr = 8; 657 p->insns = malloc(p->insns_nr * sizeof(unsigned)); 658 p->insns[0] = 0x80000000; 659 p->insns[1] = 0x9000000c; 660 p->insns[2] = 0x82010600; 661 p->insns[3] = 0x82020604; 662 p->insns[4] = 0x80030609; 663 p->insns[5] = 0x00020780; 664 p->insns[6] = 0x8004060d; 665 p->insns[7] = 0x00020781; 666 } else 667 if (pc.FullHeader.Processor.Processor == TGSI_PROCESSOR_VERTEX) { 668 int i; 669 670 if (nv50_program_tx(p) == FALSE) 671 assert(0); 672 p->insns[p->insns_nr - 1] |= 0x00000001; 673 674 for (i = 0; i < p->insns_nr; i++) 675 NOUVEAU_ERR("%d 0x%08x\n", i, p->insns[i]); 676 } else { 677 NOUVEAU_ERR("invalid TGSI processor\n"); 678 tgsi_parse_free(&pc); 679 return; 680 } 681 682 tgsi_parse_free(&pc); 683 684 p->translated = TRUE; 685} 686 687static void 688nv50_program_validate_data(struct nv50_context *nv50, struct nv50_program *p) 689{ 690 int i; 691 692 for (i = 0; i < p->immd_nr; i++) { 693 BEGIN_RING(tesla, 0x0f00, 2); 694 OUT_RING ((NV50_CB_PMISC << 16) | (i << 8)); 695 OUT_RING (fui(p->immd[i])); 696 } 697} 698 699static void 700nv50_program_validate_code(struct nv50_context *nv50, struct nv50_program *p) 701{ 702 struct pipe_winsys *ws = nv50->pipe.winsys; 703 void *map; 704 705 if (!p->buffer) 706 p->buffer = ws->buffer_create(ws, 0x100, 0, p->insns_nr * 4); 707 map = ws->buffer_map(ws, p->buffer, PIPE_BUFFER_USAGE_CPU_WRITE); 708 memcpy(map, p->insns, p->insns_nr * 4); 709 ws->buffer_unmap(ws, p->buffer); 710} 711 712void 713nv50_vertprog_validate(struct nv50_context *nv50) 714{ 715 struct nouveau_grobj *tesla = nv50->screen->tesla; 716 struct nv50_program *p = nv50->vertprog; 717 struct nouveau_stateobj *so; 718 719 if (!p->translated) { 720 nv50_program_validate(nv50, p); 721 if (!p->translated) 722 assert(0); 723 } 724 725 nv50_program_validate_data(nv50, p); 726 nv50_program_validate_code(nv50, p); 727 728 so = so_new(11, 2); 729 so_method(so, tesla, NV50TCL_VP_ADDRESS_HIGH, 2); 730 so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | 731 NOUVEAU_BO_HIGH, 0, 0); 732 so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | 733 NOUVEAU_BO_LOW, 0, 0); 734 so_method(so, tesla, 0x1650, 2); 735 so_data (so, p->cfg.vp.attr[0]); 736 so_data (so, p->cfg.vp.attr[1]); 737 so_method(so, tesla, 0x16ac, 2); 738 so_data (so, 8); 739 so_data (so, p->cfg.vp.high_temp); 740 so_method(so, tesla, 0x140c, 1); 741 so_data (so, 0); /* program start offset */ 742 so_emit(nv50->screen->nvws, so); 743 so_ref(NULL, &so); 744} 745 746void 747nv50_fragprog_validate(struct nv50_context *nv50) 748{ 749 struct pipe_winsys *ws = nv50->pipe.winsys; 750 struct nouveau_grobj *tesla = nv50->screen->tesla; 751 struct nv50_program *p = nv50->fragprog; 752 struct nouveau_stateobj *so; 753 void *map; 754 755 if (!p->translated) { 756 nv50_program_validate(nv50, p); 757 if (!p->translated) 758 assert(0); 759 } 760 761 if (!p->buffer) 762 p->buffer = ws->buffer_create(ws, 0x100, 0, p->insns_nr * 4); 763 map = ws->buffer_map(ws, p->buffer, PIPE_BUFFER_USAGE_CPU_WRITE); 764 memcpy(map, p->insns, p->insns_nr * 4); 765 ws->buffer_unmap(ws, p->buffer); 766 767 so = so_new(3, 2); 768 so_method(so, tesla, NV50TCL_FP_ADDRESS_HIGH, 2); 769 so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | 770 NOUVEAU_BO_HIGH, 0, 0); 771 so_reloc (so, p->buffer, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | 772 NOUVEAU_BO_LOW, 0, 0); 773 so_emit(nv50->screen->nvws, so); 774 so_ref(NULL, &so); 775} 776 777void 778nv50_program_destroy(struct nv50_context *nv50, struct nv50_program *p) 779{ 780 struct pipe_winsys *ws = nv50->pipe.winsys; 781 782 if (p->insns_nr) { 783 if (p->insns) 784 FREE(p->insns); 785 p->insns_nr = 0; 786 } 787 788 if (p->buffer) 789 pipe_buffer_reference(ws, &p->buffer, NULL); 790 791 p->translated = 0; 792} 793 794