• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "radeon_compiler.h"
7 
8 #include <stdio.h>
9 
10 #include "r300_fragprog.h"
11 #include "r300_fragprog_swizzle.h"
12 #include "r500_fragprog.h"
13 #include "radeon_compiler_util.h"
14 #include "radeon_dataflow.h"
15 #include "radeon_list.h"
16 #include "radeon_program_alu.h"
17 #include "radeon_program_tex.h"
18 #include "radeon_remove_constants.h"
19 #include "radeon_variable.h"
20 
21 static void
rc_rewrite_depth_out(struct radeon_compiler * cc,void * user)22 rc_rewrite_depth_out(struct radeon_compiler *cc, void *user)
23 {
24    struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler *)cc;
25    struct rc_instruction *rci;
26 
27    for (rci = c->Base.Program.Instructions.Next; rci != &c->Base.Program.Instructions;
28         rci = rci->Next) {
29       struct rc_sub_instruction *inst = &rci->U.I;
30       unsigned i;
31       const struct rc_opcode_info *info = rc_get_opcode_info(inst->Opcode);
32 
33       if (inst->DstReg.File != RC_FILE_OUTPUT || inst->DstReg.Index != c->OutputDepth)
34          continue;
35 
36       if (inst->DstReg.WriteMask & RC_MASK_Z) {
37          inst->DstReg.WriteMask = RC_MASK_W;
38       } else {
39          inst->DstReg.WriteMask = 0;
40          continue;
41       }
42 
43       if (!info->IsComponentwise) {
44          continue;
45       }
46 
47       for (i = 0; i < info->NumSrcRegs; i++) {
48          inst->SrcReg[i] = lmul_swizzle(RC_SWIZZLE_ZZZZ, inst->SrcReg[i]);
49       }
50    }
51 }
52 
53 /**
54  * This function will try to convert rgb instructions into alpha instructions
55  * and vice versa. While this is already attempted during the pair scheduling,
56  * it is much simpler to do it before pair conversion, so do it here at least for
57  * the simple cases.
58  *
59  * Currently only math opcodes writing to rgb (and with no friends) are
60  * converted to alpha.
61  *
62  * This function assumes all the instructions are still of type
63  * RC_INSTRUCTION_NORMAL, the conversion is much simpler.
64  *
65  * Beware that this needs to be also called before doing presubtract, because
66  * rc_get_variables can't get properly readers for normal instructions if presubtract
67  * is present (it works fine for pair instructions).
68  */
69 static void
rc_convert_rgb_alpha(struct radeon_compiler * c,void * user)70 rc_convert_rgb_alpha(struct radeon_compiler *c, void *user)
71 {
72    struct rc_list *variables;
73    struct rc_list *var_ptr;
74 
75    variables = rc_get_variables(c);
76 
77    for (var_ptr = variables; var_ptr; var_ptr = var_ptr->Next) {
78       struct rc_variable *var = var_ptr->Item;
79 
80       if (var->Inst->U.I.DstReg.File != RC_FILE_TEMPORARY) {
81          continue;
82       }
83 
84       /* Only rewrite scalar opcodes that are used separately for now. */
85       if (var->Friend)
86          continue;
87 
88       const struct rc_opcode_info *opcode = rc_get_opcode_info(var->Inst->U.I.Opcode);
89       if (opcode->IsStandardScalar && var->Dst.WriteMask != RC_MASK_W) {
90          unsigned index = rc_find_free_temporary(c);
91          rc_variable_change_dst(var, index, RC_MASK_W);
92       }
93 
94       /* Here we attempt to convert some code specific for the shadow lowering to use the W
95        * channel. Most notably this prevents some unfavorable presubtract later.
96        *
97        * TODO: This should not be needed once we can properly vectorize the reference value
98        * comparisons.
99        */
100       if (var->Inst->U.I.Opcode == RC_OPCODE_ADD &&
101           var->Inst->U.I.SrcReg[0].File == RC_FILE_TEMPORARY &&
102           var->Inst->U.I.SrcReg[1].File == RC_FILE_TEMPORARY &&
103           var->Inst->U.I.DstReg.File == RC_FILE_TEMPORARY &&
104           var->Inst->U.I.DstReg.WriteMask == RC_MASK_X) {
105          unsigned have_tex = false;
106          struct rc_variable *fsat = NULL;
107          for (unsigned int src = 0; src < 2; src++) {
108             struct rc_list *writer_list;
109             writer_list = rc_variable_list_get_writers(variables, RC_INSTRUCTION_NORMAL,
110                                                        &var->Inst->U.I.SrcReg[src]);
111             if (!writer_list || !writer_list->Item)
112                continue;
113 
114             struct rc_variable *src_variable = (struct rc_variable *)writer_list->Item;
115             struct rc_instruction *inst = src_variable->Inst;
116             const struct rc_opcode_info *info = rc_get_opcode_info(inst->U.I.Opcode);
117 
118             /* Here we check that the two sources are the depth texture and saturated MOV/MUL */
119             if (info->HasTexture && inst->U.I.DstReg.WriteMask == RC_MASK_X && !have_tex && !src_variable->Friend) {
120                have_tex = true;
121             }
122             if ((inst->U.I.Opcode == RC_OPCODE_MOV || inst->U.I.Opcode == RC_OPCODE_ADD) && !fsat &&
123                 inst->U.I.SaturateMode != RC_SATURATE_NONE && inst->U.I.DstReg.WriteMask == RC_MASK_X &&
124                 !src_variable->Friend) {
125                fsat = src_variable;
126             }
127          }
128 
129          /* Move the calculations to W. */
130          if (fsat && have_tex) {
131             unsigned index = rc_find_free_temporary(c);
132             rc_variable_change_dst(var, index, RC_MASK_W);
133             index = rc_find_free_temporary(c);
134             rc_variable_change_dst(fsat, index, RC_MASK_W);
135          }
136       }
137    }
138 }
139 
140 void
r3xx_compile_fragment_program(struct r300_fragment_program_compiler * c)141 r3xx_compile_fragment_program(struct r300_fragment_program_compiler *c)
142 {
143    int is_r500 = c->Base.is_r500;
144    int opt = !c->Base.disable_optimizations;
145    int alpha2one = c->state.alpha_to_one;
146    bool dbg = c->Base.Debug & RC_DBG_LOG;
147 
148    /* Lists of instruction transformations. */
149    struct radeon_program_transformation force_alpha_to_one[] = {{&rc_force_output_alpha_to_one, c},
150                                                                 {NULL, NULL}};
151 
152    struct radeon_program_transformation rewrite_tex[] = {{&radeonTransformTEX, c}, {NULL, NULL}};
153 
154    struct radeon_program_transformation native_rewrite_r500[] = {{&radeonTransformALU, NULL},
155                                                                  {&radeonTransformDeriv, NULL},
156                                                                  {NULL, NULL}};
157 
158    struct radeon_program_transformation native_rewrite_r300[] = {{&radeonTransformALU, NULL},
159                                                                  {&radeonStubDeriv, NULL},
160                                                                  {NULL, NULL}};
161 
162    struct radeon_program_transformation opt_presubtract[] = {{&rc_opt_presubtract, NULL},
163                                                              {NULL, NULL}};
164 
165    /* List of compiler passes. */
166    /* clang-format off */
167    struct radeon_compiler_pass fs_list[] = {
168       /* NAME                     DUMP PREDICATE        FUNCTION                        PARAM */
169       {"rewrite depth out",       1,   1,               rc_rewrite_depth_out,           NULL},
170       {"force alpha to one",      1,   alpha2one,       rc_local_transform,             force_alpha_to_one},
171       {"transform TEX",           1,   1,               rc_local_transform,             rewrite_tex},
172       {"transform IF",            1,   is_r500,         r500_transform_IF,              NULL},
173       {"native rewrite",          1,   is_r500,         rc_local_transform,             native_rewrite_r500},
174       {"native rewrite",          1,   !is_r500,        rc_local_transform,             native_rewrite_r300},
175       {"deadcode",                1,   opt,             rc_dataflow_deadcode,           NULL},
176       {"convert rgb<->alpha",     1,   opt,             rc_convert_rgb_alpha,           NULL},
177       {"dataflow optimize",       1,   opt,             rc_optimize,                    NULL},
178       {"inline literals",         1,   is_r500 && opt,  rc_inline_literals,             NULL},
179       {"dataflow swizzles",       1,   1,               rc_dataflow_swizzles,           NULL},
180       {"dead constants",          1,   1,               rc_remove_unused_constants,     &c->code->constants_remap_table},
181       {"dataflow presubtract",    1,   opt,             rc_local_transform,             opt_presubtract},
182       {"pair translate",          1,   1,               rc_pair_translate,              NULL},
183       {"pair scheduling",         1,   1,               rc_pair_schedule,               &opt},
184       {"dead sources",            1,   1,               rc_pair_remove_dead_sources,    NULL},
185       {"register allocation",     1,   1,               rc_pair_regalloc,               &opt},
186       {"final code validation",   0,   1,               rc_validate_final_shader,       NULL},
187       {"machine code generation", 0,   is_r500,         r500BuildFragmentProgramHwCode, NULL},
188       {"machine code generation", 0,   !is_r500,        r300BuildFragmentProgramHwCode, NULL},
189       {"dump machine code",       0,   is_r500 && dbg,  r500FragmentProgramDump,        NULL},
190       {"dump machine code",       0,   !is_r500 && dbg, r300FragmentProgramDump,        NULL},
191       {NULL,                      0,   0,               NULL,                           NULL}};
192    /* clang-format on */
193 
194    c->Base.type = RC_FRAGMENT_PROGRAM;
195    c->Base.SwizzleCaps = c->Base.is_r500 ? &r500_swizzle_caps : &r300_swizzle_caps;
196 
197    rc_run_compiler(&c->Base, fs_list);
198 
199    rc_constants_copy(&c->code->constants, &c->Base.Program.Constants);
200 }
201