2 * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 #include "radeon_compiler.h"
27 #include "radeon_compiler_util.h"
28 #include "radeon_dataflow.h"
29 #include "radeon_emulate_branches.h"
30 #include "radeon_emulate_loops.h"
31 #include "radeon_program_alu.h"
32 #include "radeon_program_tex.h"
33 #include "radeon_rename_regs.h"
34 #include "radeon_remove_constants.h"
35 #include "r300_fragprog.h"
36 #include "r300_fragprog_swizzle.h"
37 #include "r500_fragprog.h"
40 static void dataflow_outputs_mark_use(void * userdata
, void * data
,
41 void (*callback
)(void *, unsigned int, unsigned int))
43 struct r300_fragment_program_compiler
* c
= userdata
;
44 callback(data
, c
->OutputColor
[0], RC_MASK_XYZW
);
45 callback(data
, c
->OutputColor
[1], RC_MASK_XYZW
);
46 callback(data
, c
->OutputColor
[2], RC_MASK_XYZW
);
47 callback(data
, c
->OutputColor
[3], RC_MASK_XYZW
);
48 callback(data
, c
->OutputDepth
, RC_MASK_W
);
51 static void rc_rewrite_depth_out(struct radeon_compiler
*cc
, void *user
)
53 struct r300_fragment_program_compiler
*c
= (struct r300_fragment_program_compiler
*)cc
;
54 struct rc_instruction
*rci
;
56 for (rci
= c
->Base
.Program
.Instructions
.Next
; rci
!= &c
->Base
.Program
.Instructions
; rci
= rci
->Next
) {
57 struct rc_sub_instruction
* inst
= &rci
->U
.I
;
59 const struct rc_opcode_info
*info
= rc_get_opcode_info(inst
->Opcode
);
61 if (inst
->DstReg
.File
!= RC_FILE_OUTPUT
|| inst
->DstReg
.Index
!= c
->OutputDepth
)
64 if (inst
->DstReg
.WriteMask
& RC_MASK_Z
) {
65 inst
->DstReg
.WriteMask
= RC_MASK_W
;
67 inst
->DstReg
.WriteMask
= 0;
71 if (!info
->IsComponentwise
) {
75 for (i
= 0; i
< info
->NumSrcRegs
; i
++) {
76 inst
->SrcReg
[i
] = lmul_swizzle(RC_SWIZZLE_ZZZZ
, inst
->SrcReg
[i
]);
81 void r3xx_compile_fragment_program(struct r300_fragment_program_compiler
* c
)
83 int is_r500
= c
->Base
.is_r500
;
84 int kill_consts
= c
->Base
.remove_unused_constants
;
85 int opt
= !c
->Base
.disable_optimizations
;
87 /* Lists of instruction transformations. */
88 struct radeon_program_transformation rewrite_tex
[] = {
89 { &radeonTransformTEX
, c
},
93 struct radeon_program_transformation native_rewrite_r500
[] = {
94 { &r500_transform_IF
, 0 },
95 { &radeonTransformALU
, 0 },
96 { &radeonTransformDeriv
, 0 },
97 { &radeonTransformTrigScale
, 0 },
101 struct radeon_program_transformation native_rewrite_r300
[] = {
102 { &radeonTransformALU
, 0 },
103 { &r300_transform_trig_simple
, 0 },
107 /* List of compiler passes. */
108 struct radeon_compiler_pass fs_list
[] = {
109 /* NAME DUMP PREDICATE FUNCTION PARAM */
110 {"rewrite depth out", 1, 1, rc_rewrite_depth_out
, NULL
},
111 /* This transformation needs to be done before any of the IF
112 * instructions are modified. */
113 {"transform KILP", 1, 1, rc_transform_KILP
, NULL
},
114 {"unroll loops", 1, is_r500
, rc_unroll_loops
, NULL
},
115 {"transform loops", 1, !is_r500
, rc_transform_loops
, NULL
},
116 {"emulate branches", 1, !is_r500
, rc_emulate_branches
, NULL
},
117 {"transform TEX", 1, 1, rc_local_transform
, rewrite_tex
},
118 {"native rewrite", 1, is_r500
, rc_local_transform
, native_rewrite_r500
},
119 {"native rewrite", 1, !is_r500
, rc_local_transform
, native_rewrite_r300
},
120 {"deadcode", 1, opt
, rc_dataflow_deadcode
, dataflow_outputs_mark_use
},
121 {"emulate loops", 1, !is_r500
, rc_emulate_loops
, NULL
},
122 {"dataflow optimize", 1, opt
, rc_optimize
, NULL
},
123 {"dataflow swizzles", 1, 1, rc_dataflow_swizzles
, NULL
},
124 {"dead constants", 1, kill_consts
, rc_remove_unused_constants
, &c
->code
->constants_remap_table
},
125 /* This pass makes it easier for the scheduler to group TEX
126 * instructions and reduces the chances of creating too
127 * many texture indirections.*/
128 {"register rename", 1, !is_r500
|| opt
, rc_rename_regs
, NULL
},
129 {"pair translate", 1, 1, rc_pair_translate
, NULL
},
130 {"pair scheduling", 1, 1, rc_pair_schedule
, NULL
},
131 {"register allocation", 1, opt
, rc_pair_regalloc
, NULL
},
132 {"dumb register allocation", 1, !opt
, rc_pair_regalloc_inputs_only
, NULL
},
133 {"final code validation", 0, 1, rc_validate_final_shader
, NULL
},
134 {"machine code generation", 0, is_r500
, r500BuildFragmentProgramHwCode
, NULL
},
135 {"machine code generation", 0, !is_r500
, r300BuildFragmentProgramHwCode
, NULL
},
136 {"dump machine code", 0, is_r500
&& (c
->Base
.Debug
& RC_DBG_LOG
), r500FragmentProgramDump
, NULL
},
137 {"dump machine code", 0, !is_r500
&& (c
->Base
.Debug
& RC_DBG_LOG
), r300FragmentProgramDump
, NULL
},
138 {NULL
, 0, 0, NULL
, NULL
}
141 c
->Base
.type
= RC_FRAGMENT_PROGRAM
;
142 c
->Base
.SwizzleCaps
= c
->Base
.is_r500
? &r500_swizzle_caps
: &r300_swizzle_caps
;
144 rc_run_compiler(&c
->Base
, fs_list
);
146 rc_constants_copy(&c
->code
->constants
, &c
->Base
.Program
.Constants
);