merge from master
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_shader.c
1 /*
2 * Copyright (C) 2006 Ben Skeggs.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28 /*
29 * Authors:
30 * Ben Skeggs <darktama@iinet.net.au>
31 */
32
33 #include "glheader.h"
34 #include "macros.h"
35 #include "enums.h"
36 #include "extensions.h"
37
38 #include "shader/program.h"
39 #include "shader/prog_instruction.h"
40 /*#include "shader/arbprogparse.h"*/
41 #include "tnl/tnl.h"
42
43 #include "nouveau_context.h"
44 #include "nouveau_shader.h"
45
46 /*****************************************************************************
47 * Mesa entry points
48 */
49 static void
50 nouveauBindProgram(GLcontext *ctx, GLenum target, struct gl_program *prog)
51 {
52 NVSDBG("target=%s, prog=%p\n", _mesa_lookup_enum_by_nr(target), prog);
53 }
54
55 static struct gl_program *
56 nouveauNewProgram(GLcontext *ctx, GLenum target, GLuint id)
57 {
58 nouveauShader *nvs;
59
60 NVSDBG("target=%s, id=%d\n", _mesa_lookup_enum_by_nr(target), id);
61
62 nvs = CALLOC_STRUCT(_nouveauShader);
63 NVSDBG("prog=%p\n", nvs);
64 switch (target) {
65 case GL_VERTEX_PROGRAM_ARB:
66 return _mesa_init_vertex_program(ctx, &nvs->mesa.vp, target, id);
67 case GL_FRAGMENT_PROGRAM_ARB:
68 return _mesa_init_fragment_program(ctx, &nvs->mesa.fp, target, id);
69 default:
70 _mesa_problem(ctx, "Unsupported shader target");
71 break;
72 }
73
74 FREE(nvs);
75 return NULL;
76 }
77
78 static void
79 nouveauDeleteProgram(GLcontext *ctx, struct gl_program *prog)
80 {
81 nouveauShader *nvs = (nouveauShader *)prog;
82
83 NVSDBG("prog=%p\n", prog);
84
85 if (nvs->translated)
86 FREE(nvs->program);
87 _mesa_delete_program(ctx, prog);
88 }
89
90 static void
91 nouveauProgramStringNotify(GLcontext *ctx, GLenum target,
92 struct gl_program *prog)
93 {
94 nouveauShader *nvs = (nouveauShader *)prog;
95
96 NVSDBG("target=%s, prog=%p\n", _mesa_lookup_enum_by_nr(target), prog);
97
98 if (nvs->translated)
99 FREE(nvs->program);
100
101 nvs->error = GL_FALSE;
102 nvs->translated = GL_FALSE;
103
104 _tnl_program_string(ctx, target, prog);
105 }
106
107 static GLboolean
108 nouveauIsProgramNative(GLcontext * ctx, GLenum target, struct gl_program *prog)
109 {
110 nouveauShader *nvs = (nouveauShader *)prog;
111
112 NVSDBG("target=%s, prog=%p\n", _mesa_lookup_enum_by_nr(target), prog);
113
114 return nvs->translated;
115 }
116
117 GLboolean
118 nvsUpdateShader(GLcontext *ctx, nouveauShader *nvs)
119 {
120 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
121 struct gl_program_parameter_list *plist;
122 int i;
123
124 NVSDBG("prog=%p\n", nvs);
125
126 /* Translate to HW format now if necessary */
127 if (!nvs->translated) {
128 /* Mesa ASM shader -> nouveauShader */
129 if (!nouveau_shader_pass0(ctx, nvs))
130 return GL_FALSE;
131 /* Basic dead code elimination + register usage info */
132 if (!nouveau_shader_pass1(nvs))
133 return GL_FALSE;
134 /* nouveauShader -> HW bytecode, HW register alloc */
135 if (!nouveau_shader_pass2(nvs))
136 return GL_FALSE;
137 assert(nvs->translated);
138 assert(nvs->program);
139 }
140
141 /* Update state parameters */
142 plist = nvs->mesa.vp.Base.Parameters;
143 _mesa_load_state_parameters(ctx, plist);
144 for (i=0; i<nvs->param_high; i++) {
145 if (!nvs->params[i].in_use)
146 continue;
147
148 if (!nvs->on_hardware) {
149 /* if we've been kicked off the hardware there's no guarantee our
150 * consts are still there.. reupload them all
151 */
152 nvs->func->UpdateConst(ctx, nvs, i);
153 } else if (nvs->params[i].source_val) {
154 /* update any changed state parameters */
155 if (!TEST_EQ_4V(nvs->params[i].val, nvs->params[i].source_val))
156 nvs->func->UpdateConst(ctx, nvs, i);
157 }
158 }
159
160 /* Upload program to hardware, this must come after state param update
161 * as >=NV30 fragprogs inline consts into the bytecode.
162 */
163 if (!nvs->on_hardware) {
164 nouveauShader **current;
165
166 if (nvs->mesa.vp.Base.Target == GL_VERTEX_PROGRAM_ARB)
167 current = &nmesa->current_vertprog;
168 else
169 current = &nmesa->current_fragprog;
170 if (*current) (*current)->on_hardware = 0;
171
172 nvs->func->UploadToHW(ctx, nvs);
173 nvs->on_hardware = 1;
174
175 *current = nvs;
176 }
177
178 return GL_TRUE;
179 }
180
181 nouveauShader *
182 nvsBuildTextShader(GLcontext *ctx, GLenum target, const char *text)
183 {
184 nouveauShader *nvs;
185
186 nvs = CALLOC_STRUCT(_nouveauShader);
187 if (!nvs)
188 return NULL;
189
190 if (target == GL_VERTEX_PROGRAM_ARB) {
191 _mesa_init_vertex_program(ctx, &nvs->mesa.vp, GL_VERTEX_PROGRAM_ARB, 0);
192 _mesa_parse_arb_vertex_program(ctx,
193 GL_VERTEX_PROGRAM_ARB,
194 text,
195 strlen(text),
196 &nvs->mesa.vp);
197 } else if (target == GL_FRAGMENT_PROGRAM_ARB) {
198 _mesa_init_fragment_program(ctx, &nvs->mesa.fp, GL_FRAGMENT_PROGRAM_ARB, 0);
199 _mesa_parse_arb_fragment_program(ctx,
200 GL_FRAGMENT_PROGRAM_ARB,
201 text,
202 strlen(text),
203 &nvs->mesa.fp);
204 }
205
206 nouveau_shader_pass0(ctx, nvs);
207 nouveau_shader_pass1(nvs);
208 nouveau_shader_pass2(nvs);
209
210 return nvs;
211 }
212
213 static void
214 nvsBuildPassthroughVP(GLcontext *ctx)
215 {
216 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
217
218 const char *vp_text =
219 "!!ARBvp1.0\n"
220 "OPTION ARB_position_invariant;"
221 ""
222 "MOV result.color, vertex.color;\n"
223 "MOV result.texcoord[0], vertex.texcoord[0];\n"
224 "MOV result.texcoord[1], vertex.texcoord[1];\n"
225 "MOV result.texcoord[2], vertex.texcoord[2];\n"
226 "MOV result.texcoord[3], vertex.texcoord[3];\n"
227 "MOV result.texcoord[4], vertex.texcoord[4];\n"
228 "MOV result.texcoord[5], vertex.texcoord[5];\n"
229 "MOV result.texcoord[6], vertex.texcoord[6];\n"
230 "MOV result.texcoord[7], vertex.texcoord[7];\n"
231 "END";
232
233 nmesa->passthrough_vp = nvsBuildTextShader(ctx,
234 GL_VERTEX_PROGRAM_ARB,
235 vp_text);
236 }
237
238 static void
239 nvsBuildPassthroughFP(GLcontext *ctx)
240 {
241 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
242
243 const char *fp_text =
244 "!!ARBfp1.0\n"
245 "MOV result.color, fragment.color;\n"
246 "END";
247
248 nmesa->passthrough_fp = nvsBuildTextShader(ctx,
249 GL_FRAGMENT_PROGRAM_ARB,
250 fp_text);
251 }
252
253 void
254 nouveauShaderInitFuncs(GLcontext * ctx)
255 {
256 nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
257
258 switch (nmesa->screen->card->type) {
259 case NV_20:
260 NV20VPInitShaderFuncs(&nmesa->VPfunc);
261 break;
262 case NV_30:
263 NV30VPInitShaderFuncs(&nmesa->VPfunc);
264 NV30FPInitShaderFuncs(&nmesa->FPfunc);
265 break;
266 case NV_40:
267 case NV_44:
268 NV40VPInitShaderFuncs(&nmesa->VPfunc);
269 NV40FPInitShaderFuncs(&nmesa->FPfunc);
270 break;
271 case NV_50:
272 default:
273 return;
274 }
275
276 /* Build a vertex program that simply passes through all attribs.
277 * Needed to do swtcl on nv40
278 */
279 if (nmesa->screen->card->type >= NV_40)
280 nvsBuildPassthroughVP(ctx);
281
282 /* Needed on NV30, even when using swtcl, if you want to get colours */
283 if (nmesa->screen->card->type >= NV_30)
284 nvsBuildPassthroughFP(ctx);
285
286 ctx->Const.VertexProgram.MaxNativeInstructions = nmesa->VPfunc.MaxInst;
287 ctx->Const.VertexProgram.MaxNativeAluInstructions = nmesa->VPfunc.MaxInst;
288 ctx->Const.VertexProgram.MaxNativeTexInstructions = nmesa->VPfunc.MaxInst;
289 ctx->Const.VertexProgram.MaxNativeTexIndirections =
290 ctx->Const.VertexProgram.MaxNativeTexInstructions;
291 ctx->Const.VertexProgram.MaxNativeAttribs = nmesa->VPfunc.MaxAttrib;
292 ctx->Const.VertexProgram.MaxNativeTemps = nmesa->VPfunc.MaxTemp;
293 ctx->Const.VertexProgram.MaxNativeAddressRegs = nmesa->VPfunc.MaxAddress;
294 ctx->Const.VertexProgram.MaxNativeParameters = nmesa->VPfunc.MaxConst;
295
296 if (nmesa->screen->card->type >= NV_30) {
297 ctx->Const.FragmentProgram.MaxNativeInstructions = nmesa->FPfunc.MaxInst;
298 ctx->Const.FragmentProgram.MaxNativeAluInstructions = nmesa->FPfunc.MaxInst;
299 ctx->Const.FragmentProgram.MaxNativeTexInstructions = nmesa->FPfunc.MaxInst;
300 ctx->Const.FragmentProgram.MaxNativeTexIndirections =
301 ctx->Const.FragmentProgram.MaxNativeTexInstructions;
302 ctx->Const.FragmentProgram.MaxNativeAttribs = nmesa->FPfunc.MaxAttrib;
303 ctx->Const.FragmentProgram.MaxNativeTemps = nmesa->FPfunc.MaxTemp;
304 ctx->Const.FragmentProgram.MaxNativeAddressRegs = nmesa->FPfunc.MaxAddress;
305 ctx->Const.FragmentProgram.MaxNativeParameters = nmesa->FPfunc.MaxConst;
306 }
307
308 ctx->Driver.NewProgram = nouveauNewProgram;
309 ctx->Driver.BindProgram = nouveauBindProgram;
310 ctx->Driver.DeleteProgram = nouveauDeleteProgram;
311 ctx->Driver.ProgramStringNotify = nouveauProgramStringNotify;
312 ctx->Driver.IsProgramNative = nouveauIsProgramNative;
313 }
314
315
316 /*****************************************************************************
317 * Disassembly support structs
318 */
319 #define CHECK_RANGE(idx, arr) ((idx)<sizeof(_##arr)/sizeof(const char *)) \
320 ? _##arr[(idx)] : #arr"_OOB"
321
322 #define NODS (1<<0)
323 #define BRANCH_TR (1<<1)
324 #define BRANCH_EL (1<<2)
325 #define BRANCH_EN (1<<3)
326 #define BRANCH_RE (1<<4)
327 #define BRANCH_ALL (BRANCH_TR|BRANCH_EL|BRANCH_EN)
328 #define COUNT_INC (1<<4)
329 #define COUNT_IND (1<<5)
330 #define COUNT_NUM (1<<6)
331 #define COUNT_ALL (COUNT_INC|COUNT_IND|COUNT_NUM)
332 #define TI_UNIT (1<<7)
333 struct _opcode_info
334 {
335 const char *name;
336 int numsrc;
337 int flags;
338 };
339
340 static struct _opcode_info ops[] = {
341 [NVS_OP_ABS] = {"ABS", 1, 0},
342 [NVS_OP_ADD] = {"ADD", 2, 0},
343 [NVS_OP_ARA] = {"ARA", 1, 0},
344 [NVS_OP_ARL] = {"ARL", 1, 0},
345 [NVS_OP_ARR] = {"ARR", 1, 0},
346 [NVS_OP_BRA] = {"BRA", 0, NODS | BRANCH_TR},
347 [NVS_OP_BRK] = {"BRK", 0, NODS},
348 [NVS_OP_CAL] = {"CAL", 0, NODS | BRANCH_TR},
349 [NVS_OP_CMP] = {"CMP", 2, 0},
350 [NVS_OP_COS] = {"COS", 1, 0},
351 [NVS_OP_DIV] = {"DIV", 2, 0},
352 [NVS_OP_DDX] = {"DDX", 1, 0},
353 [NVS_OP_DDY] = {"DDY", 1, 0},
354 [NVS_OP_DP2] = {"DP2", 2, 0},
355 [NVS_OP_DP2A] = {"DP2A", 3, 0},
356 [NVS_OP_DP3] = {"DP3", 2, 0},
357 [NVS_OP_DP4] = {"DP4", 2, 0},
358 [NVS_OP_DPH] = {"DPH", 2, 0},
359 [NVS_OP_DST] = {"DST", 2, 0},
360 [NVS_OP_EX2] = {"EX2", 1, 0},
361 [NVS_OP_EXP] = {"EXP", 1, 0},
362 [NVS_OP_FLR] = {"FLR", 1, 0},
363 [NVS_OP_FRC] = {"FRC", 1, 0},
364 [NVS_OP_IF] = {"IF", 0, NODS | BRANCH_EL | BRANCH_EN},
365 [NVS_OP_KIL] = {"KIL", 1, 0},
366 [NVS_OP_LG2] = {"LG2", 1, 0},
367 [NVS_OP_LIT] = {"LIT", 1, 0},
368 [NVS_OP_LOG] = {"LOG", 1, 0},
369 [NVS_OP_LOOP] = {"LOOP", 0, NODS | COUNT_ALL | BRANCH_EN},
370 [NVS_OP_LRP] = {"LRP", 3, 0},
371 [NVS_OP_MAD] = {"MAD", 3, 0},
372 [NVS_OP_MAX] = {"MAX", 2, 0},
373 [NVS_OP_MIN] = {"MIN", 2, 0},
374 [NVS_OP_MOV] = {"MOV", 1, 0},
375 [NVS_OP_MUL] = {"MUL", 2, 0},
376 [NVS_OP_NRM] = {"NRM", 1, 0},
377 [NVS_OP_PK2H] = {"PK2H", 1, 0},
378 [NVS_OP_PK2US] = {"PK2US", 1, 0},
379 [NVS_OP_PK4B] = {"PK4B", 1, 0},
380 [NVS_OP_PK4UB] = {"PK4UB", 1, 0},
381 [NVS_OP_POW] = {"POW", 2, 0},
382 [NVS_OP_POPA] = {"POPA", 0, 0},
383 [NVS_OP_PUSHA] = {"PUSHA", 1, NODS},
384 [NVS_OP_RCC] = {"RCC", 1, 0},
385 [NVS_OP_RCP] = {"RCP", 1, 0},
386 [NVS_OP_REP] = {"REP", 0, NODS | BRANCH_EN | COUNT_NUM},
387 [NVS_OP_RET] = {"RET", 0, NODS},
388 [NVS_OP_RFL] = {"RFL", 1, 0},
389 [NVS_OP_RSQ] = {"RSQ", 1, 0},
390 [NVS_OP_SCS] = {"SCS", 1, 0},
391 [NVS_OP_SEQ] = {"SEQ", 2, 0},
392 [NVS_OP_SFL] = {"SFL", 2, 0},
393 [NVS_OP_SGE] = {"SGE", 2, 0},
394 [NVS_OP_SGT] = {"SGT", 2, 0},
395 [NVS_OP_SIN] = {"SIN", 1, 0},
396 [NVS_OP_SLE] = {"SLE", 2, 0},
397 [NVS_OP_SLT] = {"SLT", 2, 0},
398 [NVS_OP_SNE] = {"SNE", 2, 0},
399 [NVS_OP_SSG] = {"SSG", 1, 0},
400 [NVS_OP_STR] = {"STR", 2, 0},
401 [NVS_OP_SUB] = {"SUB", 2, 0},
402 [NVS_OP_TEX] = {"TEX", 1, TI_UNIT},
403 [NVS_OP_TXB] = {"TXB", 1, TI_UNIT},
404 [NVS_OP_TXD] = {"TXD", 3, TI_UNIT},
405 [NVS_OP_TXL] = {"TXL", 1, TI_UNIT},
406 [NVS_OP_TXP] = {"TXP", 1, TI_UNIT},
407 [NVS_OP_UP2H] = {"UP2H", 1, 0},
408 [NVS_OP_UP2US] = {"UP2US", 1, 0},
409 [NVS_OP_UP4B] = {"UP4B", 1, 0},
410 [NVS_OP_UP4UB] = {"UP4UB", 1, 0},
411 [NVS_OP_X2D] = {"X2D", 3, 0},
412 [NVS_OP_XPD] = {"XPD", 2, 0},
413 [NVS_OP_NOP] = {"NOP", 0, NODS},
414 };
415
416 static struct _opcode_info *
417 _get_op_info(int op)
418 {
419 if (op >= (sizeof(ops) / sizeof(struct _opcode_info)))
420 return NULL;
421 if (ops[op].name == NULL)
422 return NULL;
423 return &ops[op];
424 }
425
426 static const char *_SFR_STRING[] = {
427 [NVS_FR_POSITION] = "position",
428 [NVS_FR_WEIGHT] = "weight",
429 [NVS_FR_NORMAL] = "normal",
430 [NVS_FR_COL0] = "color",
431 [NVS_FR_COL1] = "color.secondary",
432 [NVS_FR_BFC0] = "bfc",
433 [NVS_FR_BFC1] = "bfc.secondary",
434 [NVS_FR_FOGCOORD] = "fogcoord",
435 [NVS_FR_POINTSZ] = "pointsize",
436 [NVS_FR_TEXCOORD0] = "texcoord[0]",
437 [NVS_FR_TEXCOORD1] = "texcoord[1]",
438 [NVS_FR_TEXCOORD2] = "texcoord[2]",
439 [NVS_FR_TEXCOORD3] = "texcoord[3]",
440 [NVS_FR_TEXCOORD4] = "texcoord[4]",
441 [NVS_FR_TEXCOORD5] = "texcoord[5]",
442 [NVS_FR_TEXCOORD6] = "texcoord[6]",
443 [NVS_FR_TEXCOORD7] = "texcoord[7]",
444 [NVS_FR_FRAGDATA0] = "data[0]",
445 [NVS_FR_FRAGDATA1] = "data[1]",
446 [NVS_FR_FRAGDATA2] = "data[2]",
447 [NVS_FR_FRAGDATA3] = "data[3]",
448 [NVS_FR_CLIP0] = "clip_plane[0]",
449 [NVS_FR_CLIP1] = "clip_plane[1]",
450 [NVS_FR_CLIP2] = "clip_plane[2]",
451 [NVS_FR_CLIP3] = "clip_plane[3]",
452 [NVS_FR_CLIP4] = "clip_plane[4]",
453 [NVS_FR_CLIP5] = "clip_plane[5]",
454 [NVS_FR_CLIP6] = "clip_plane[6]",
455 [NVS_FR_FACING] = "facing",
456 };
457
458 #define SFR_STRING(idx) CHECK_RANGE((idx), SFR_STRING)
459
460 static const char *_SWZ_STRING[] = {
461 [NVS_SWZ_X] = "x",
462 [NVS_SWZ_Y] = "y",
463 [NVS_SWZ_Z] = "z",
464 [NVS_SWZ_W] = "w"
465 };
466
467 #define SWZ_STRING(idx) CHECK_RANGE((idx), SWZ_STRING)
468
469 static const char *_NVS_PREC_STRING[] = {
470 [NVS_PREC_FLOAT32] = "R",
471 [NVS_PREC_FLOAT16] = "H",
472 [NVS_PREC_FIXED12] = "X",
473 [NVS_PREC_UNKNOWN] = "?"
474 };
475
476 #define NVS_PREC_STRING(idx) CHECK_RANGE((idx), NVS_PREC_STRING)
477
478 static const char *_NVS_COND_STRING[] = {
479 [NVS_COND_FL] = "FL",
480 [NVS_COND_LT] = "LT",
481 [NVS_COND_EQ] = "EQ",
482 [NVS_COND_LE] = "LE",
483 [NVS_COND_GT] = "GT",
484 [NVS_COND_NE] = "NE",
485 [NVS_COND_GE] = "GE",
486 [NVS_COND_TR] = "TR",
487 [NVS_COND_UNKNOWN] = "??"
488 };
489
490 #define NVS_COND_STRING(idx) CHECK_RANGE((idx), NVS_COND_STRING)
491
492 /*****************************************************************************
493 * ShaderFragment dumping
494 */
495 static void
496 nvsDumpIndent(int lvl)
497 {
498 while (lvl--)
499 printf(" ");
500 }
501
502 static void
503 nvsDumpSwizzle(nvsSwzComp *swz)
504 {
505 printf(".%s%s%s%s",
506 SWZ_STRING(swz[0]),
507 SWZ_STRING(swz[1]), SWZ_STRING(swz[2]), SWZ_STRING(swz[3])
508 );
509 }
510
511 static void
512 nvsDumpReg(nvsInstruction * inst, nvsRegister * reg)
513 {
514 if (reg->negate)
515 printf("-");
516 if (reg->abs)
517 printf("abs(");
518
519 switch (reg->file) {
520 case NVS_FILE_TEMP:
521 printf("R%d", reg->index);
522 nvsDumpSwizzle(reg->swizzle);
523 break;
524 case NVS_FILE_ATTRIB:
525 printf("attrib.%s", SFR_STRING(reg->index));
526 nvsDumpSwizzle(reg->swizzle);
527 break;
528 case NVS_FILE_ADDRESS:
529 printf("A%d", reg->index);
530 break;
531 case NVS_FILE_CONST:
532 if (reg->indexed)
533 printf("const[A%d.%s + %d]",
534 reg->addr_reg, SWZ_STRING(reg->addr_comp), reg->index);
535 else
536 printf("const[%d]", reg->index);
537 nvsDumpSwizzle(reg->swizzle);
538 break;
539 default:
540 printf("UNKNOWN_FILE");
541 break;
542 }
543
544 if (reg->abs)
545 printf(")");
546 }
547
548 static void
549 nvsDumpInstruction(nvsInstruction * inst, int slot, int lvl)
550 {
551 struct _opcode_info *opr = &ops[inst->op];
552 int i;
553
554 nvsDumpIndent(lvl);
555 printf("%s ", opr->name);
556
557 if (!opr->flags & NODS) {
558 switch (inst->dest.file) {
559 case NVS_FILE_RESULT:
560 printf("result.%s", SFR_STRING(inst->dest.index));
561 break;
562 case NVS_FILE_TEMP:
563 printf("R%d", inst->dest.index);
564 break;
565 case NVS_FILE_ADDRESS:
566 printf("A%d", inst->dest.index);
567 break;
568 default:
569 printf("UNKNOWN_DST_FILE");
570 break;
571 }
572
573 if (inst->mask != SMASK_ALL) {
574 printf(".");
575 if (inst->mask & SMASK_X)
576 printf("x");
577 if (inst->mask & SMASK_Y)
578 printf("y");
579 if (inst->mask & SMASK_Z)
580 printf("z");
581 if (inst->mask & SMASK_W)
582 printf("w");
583 }
584
585 if (opr->numsrc)
586 printf(", ");
587 }
588
589 for (i = 0; i < opr->numsrc; i++) {
590 nvsDumpReg(inst, &inst->src[i]);
591 if (i != opr->numsrc - 1)
592 printf(", ");
593 }
594 if (opr->flags & TI_UNIT)
595 printf(", texture[%d]", inst->tex_unit);
596
597 printf("\n");
598 }
599
600 void
601 nvsDumpFragmentList(nvsFragmentHeader *f, int lvl)
602 {
603 while (f) {
604 switch (f->type) {
605 case NVS_INSTRUCTION:
606 nvsDumpInstruction((nvsInstruction*)f, 0, lvl);
607 break;
608 default:
609 fprintf(stderr, "%s: Only NVS_INSTRUCTION fragments can be in"
610 "nvsFragmentList!\n", __func__);
611 return;
612 }
613 f = f->next;
614 }
615 }
616
617 /*****************************************************************************
618 * HW shader disassembly
619 */
620 static void
621 nvsDisasmHWShaderOp(nvsFunc * shader, int merged)
622 {
623 struct _opcode_info *opi;
624 nvsOpcode op;
625 nvsRegFile file;
626 nvsSwzComp swz[4];
627 int i;
628
629 op = shader->GetOpcode(shader, merged);
630 opi = _get_op_info(op);
631 if (!opi) {
632 printf("NO OPINFO!");
633 return;
634 }
635
636 printf("%s", opi->name);
637 if (shader->GetPrecision &&
638 (!(opi->flags & BRANCH_ALL)) && (!(opi->flags * NODS)) &&
639 (op != NVS_OP_NOP))
640 printf("%s", NVS_PREC_STRING(shader->GetPrecision(shader)));
641 if (shader->SupportsConditional && shader->SupportsConditional(shader)) {
642 if (shader->GetConditionUpdate(shader)) {
643 printf("C%d", shader->GetCondRegID(shader));
644 }
645 }
646 if (shader->GetSaturate && shader->GetSaturate(shader))
647 printf("_SAT");
648
649 if (!(opi->flags & NODS)) {
650 int mask = shader->GetDestMask(shader, merged);
651
652 switch (shader->GetDestFile(shader, merged)) {
653 case NVS_FILE_ADDRESS:
654 printf(" A%d", shader->GetDestID(shader, merged));
655 break;
656 case NVS_FILE_TEMP:
657 printf(" R%d", shader->GetDestID(shader, merged));
658 break;
659 case NVS_FILE_RESULT:
660 printf(" result.%s", (SFR_STRING(shader->GetDestID(shader, merged))));
661 break;
662 default:
663 printf(" BAD_RESULT_FILE");
664 break;
665 }
666
667 if (mask != SMASK_ALL) {
668 printf(".");
669 if (mask & SMASK_X) printf("x");
670 if (mask & SMASK_Y) printf("y");
671 if (mask & SMASK_Z) printf("z");
672 if (mask & SMASK_W) printf("w");
673 }
674 }
675
676 if (shader->SupportsConditional && shader->SupportsConditional(shader) &&
677 shader->GetConditionTest(shader)) {
678 shader->GetCondRegSwizzle(shader, swz);
679
680 printf(" (%s%d.%s%s%s%s)",
681 NVS_COND_STRING(shader->GetCondition(shader)),
682 shader->GetCondRegID(shader),
683 SWZ_STRING(swz[NVS_SWZ_X]),
684 SWZ_STRING(swz[NVS_SWZ_Y]),
685 SWZ_STRING(swz[NVS_SWZ_Z]),
686 SWZ_STRING(swz[NVS_SWZ_W])
687 );
688 }
689
690 /* looping */
691 if (opi->flags & COUNT_ALL) {
692 printf(" { ");
693 if (opi->flags & COUNT_NUM) {
694 printf("%d", shader->GetLoopCount(shader));
695 }
696 if (opi->flags & COUNT_IND) {
697 printf(", %d", shader->GetLoopInitial(shader));
698 }
699 if (opi->flags & COUNT_INC) {
700 printf(", %d", shader->GetLoopIncrement(shader));
701 }
702 printf(" }");
703 }
704
705 /* branching */
706 if (opi->flags & BRANCH_TR)
707 printf(" %d", shader->GetBranch(shader));
708 if (opi->flags & BRANCH_EL)
709 printf(" ELSE %d", shader->GetBranchElse(shader));
710 if (opi->flags & BRANCH_EN)
711 printf(" END %d", shader->GetBranchEnd(shader));
712
713 if (!(opi->flags & NODS) && opi->numsrc)
714 printf(",");
715 printf(" ");
716
717 for (i = 0; i < opi->numsrc; i++) {
718 if (shader->GetSourceAbs(shader, merged, i))
719 printf("abs(");
720 if (shader->GetSourceNegate(shader, merged, i))
721 printf("-");
722
723 file = shader->GetSourceFile(shader, merged, i);
724 switch (file) {
725 case NVS_FILE_TEMP:
726 printf("R%d", shader->GetSourceID(shader, merged, i));
727 break;
728 case NVS_FILE_CONST:
729 if (shader->GetSourceIndexed(shader, merged, i)) {
730 printf("c[A%d.%s + 0x%x]",
731 shader->GetRelAddressRegID(shader),
732 SWZ_STRING(shader->GetRelAddressSwizzle(shader)),
733 shader->GetSourceID(shader, merged, i)
734 );
735 } else {
736 float val[4];
737
738 if (shader->GetSourceConstVal) {
739 shader->GetSourceConstVal(shader, merged, i, val);
740 printf("{ %.02f, %.02f, %.02f, %.02f }",
741 val[0], val[1], val[2], val[3]);
742 } else {
743 printf("c[0x%x]", shader->GetSourceID(shader, merged, i));
744 }
745 }
746 break;
747 case NVS_FILE_ATTRIB:
748 if (shader->GetSourceIndexed(shader, merged, i)) {
749 printf("attrib[A%d.%s + %d]",
750 shader->GetRelAddressRegID(shader),
751 SWZ_STRING(shader->GetRelAddressSwizzle(shader)),
752 shader->GetSourceID(shader, merged, i)
753 );
754 }
755 else {
756 printf("attrib.%s",
757 SFR_STRING(shader->GetSourceID(shader, merged, i))
758 );
759 }
760 break;
761 case NVS_FILE_ADDRESS:
762 printf("A%d", shader->GetRelAddressRegID(shader));
763 break;
764 default:
765 printf("UNKNOWN_SRC_FILE");
766 break;
767 }
768
769 shader->GetSourceSwizzle(shader, merged, i, swz);
770 if (file != NVS_FILE_ADDRESS &&
771 (swz[NVS_SWZ_X] != NVS_SWZ_X || swz[NVS_SWZ_Y] != NVS_SWZ_Y ||
772 swz[NVS_SWZ_Z] != NVS_SWZ_Z || swz[NVS_SWZ_W] != NVS_SWZ_W)) {
773 printf(".%s%s%s%s", SWZ_STRING(swz[NVS_SWZ_X]),
774 SWZ_STRING(swz[NVS_SWZ_Y]),
775 SWZ_STRING(swz[NVS_SWZ_Z]),
776 SWZ_STRING(swz[NVS_SWZ_W]));
777 }
778
779 if (shader->GetSourceAbs(shader, merged, i))
780 printf(")");
781 if (shader->GetSourceScale) {
782 int scale = shader->GetSourceScale(shader, merged, i);
783 if (scale > 1)
784 printf("{scaled %dx}", scale);
785 }
786 if (i < (opi->numsrc - 1))
787 printf(", ");
788 }
789
790 if (shader->IsLastInst(shader))
791 printf(" + END");
792 }
793
794 void
795 nvsDisasmHWShader(nvsPtr nvs)
796 {
797 nvsFunc *shader = nvs->func;
798 unsigned int iaddr = 0;
799
800 if (!nvs->program) {
801 fprintf(stderr, "No HW program present");
802 return;
803 }
804
805 shader->inst = nvs->program;
806 while (1) {
807 if (shader->inst >= (nvs->program + nvs->program_size)) {
808 fprintf(stderr, "Reached end of program, but HW inst has no END");
809 break;
810 }
811
812 printf("\t0x%08x:\n", shader->inst[0]);
813 printf("\t0x%08x:\n", shader->inst[1]);
814 printf("\t0x%08x:\n", shader->inst[2]);
815 printf("\t0x%08x:", shader->inst[3]);
816
817 printf("\n\t\tINST %d.0: ", iaddr);
818 nvsDisasmHWShaderOp(shader, 0);
819 if (shader->HasMergedInst(shader)) {
820 printf("\n\t\tINST %d.1: ", iaddr);
821 nvsDisasmHWShaderOp(shader, 1);
822 }
823 printf("\n");
824
825 if (shader->IsLastInst(shader))
826 break;
827
828 shader->inst += shader->GetOffsetNext(shader);
829 iaddr++;
830 }
831
832 printf("\n");
833 }