OSDN Git Service

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