1 /**************************************************************************
3 Copyright (C) 2005 Aapo Tahkola <aet@rasterburn.org>
4 Copyright (C) 2008 Oliver McFadden <z3ro.geek@gmail.com>
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
29 /* Radeon R5xx Acceleration, Revision 1.2 */
31 #include "main/glheader.h"
32 #include "main/macros.h"
33 #include "main/enums.h"
34 #include "shader/program.h"
35 #include "shader/programopt.h"
36 #include "shader/prog_instruction.h"
37 #include "shader/prog_optimize.h"
38 #include "shader/prog_parameter.h"
39 #include "shader/prog_print.h"
40 #include "shader/prog_statevars.h"
43 #include "compiler/radeon_compiler.h"
44 #include "compiler/radeon_nqssadce.h"
45 #include "r300_context.h"
46 #include "r300_state.h"
49 * Write parameter array for the given vertex program into dst.
50 * Return the total number of components written.
52 static int r300VertexProgUpdateParams(GLcontext
* ctx
, struct r300_vertex_program
*vp
, float *dst
)
56 if (vp
->Base
->IsNVProgram
) {
57 _mesa_load_tracked_matrices(ctx
);
59 if (vp
->Base
->Base
.Parameters
) {
60 _mesa_load_state_parameters(ctx
, vp
->Base
->Base
.Parameters
);
64 if (vp
->code
.constants
.Count
* 4 > VSF_MAX_FRAGMENT_LENGTH
) {
65 /* Should have checked this earlier... */
66 fprintf(stderr
, "%s:Params exhausted\n", __FUNCTION__
);
70 for(i
= 0; i
< vp
->code
.constants
.Count
; ++i
) {
71 const float * src
= 0;
72 const struct rc_constant
* constant
= &vp
->code
.constants
.Constants
[i
];
74 switch(constant
->Type
) {
75 case RC_CONSTANT_EXTERNAL
:
76 if (vp
->Base
->IsNVProgram
) {
77 src
= ctx
->VertexProgram
.Parameters
[constant
->u
.External
];
79 src
= vp
->Base
->Base
.Parameters
->ParameterValues
[constant
->u
.External
];
83 case RC_CONSTANT_IMMEDIATE
:
84 src
= constant
->u
.Immediate
;
89 dst
[4*i
+ 1] = src
[1];
90 dst
[4*i
+ 2] = src
[2];
91 dst
[4*i
+ 3] = src
[3];
94 return 4 * vp
->code
.constants
.Count
;
97 static GLbitfield
compute_required_outputs(struct gl_vertex_program
* vp
, GLbitfield fpreads
)
99 GLbitfield outputs
= 0;
102 #define ADD_OUTPUT(fp_attr, vp_result) \
104 if (fpreads & (1 << (fp_attr))) \
105 outputs |= (1 << (vp_result)); \
108 ADD_OUTPUT(FRAG_ATTRIB_COL0
, VERT_RESULT_COL0
);
109 ADD_OUTPUT(FRAG_ATTRIB_COL1
, VERT_RESULT_COL1
);
111 for (i
= 0; i
<= 7; ++i
) {
112 ADD_OUTPUT(FRAG_ATTRIB_TEX0
+ i
, VERT_RESULT_TEX0
+ i
);
117 if ((fpreads
& (1 << FRAG_ATTRIB_COL0
)) &&
118 (vp
->Base
.OutputsWritten
& (1 << VERT_RESULT_BFC0
)))
119 outputs
|= 1 << VERT_RESULT_BFC0
;
120 if ((fpreads
& (1 << FRAG_ATTRIB_COL1
)) &&
121 (vp
->Base
.OutputsWritten
& (1 << VERT_RESULT_BFC1
)))
122 outputs
|= 1 << VERT_RESULT_BFC1
;
124 outputs
|= 1 << VERT_RESULT_HPOS
;
125 if (vp
->Base
.OutputsWritten
& (1 << VERT_RESULT_PSIZ
))
126 outputs
|= 1 << VERT_RESULT_PSIZ
;
132 static void t_inputs_outputs(struct r300_vertex_program_compiler
* c
)
136 GLuint OutputsWritten
, InputsRead
;
138 OutputsWritten
= c
->Base
.Program
.OutputsWritten
;
139 InputsRead
= c
->Base
.Program
.InputsRead
;
142 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++) {
143 if (InputsRead
& (1 << i
))
144 c
->code
->inputs
[i
] = ++cur_reg
;
146 c
->code
->inputs
[i
] = -1;
150 for (i
= 0; i
< VERT_RESULT_MAX
; i
++)
151 c
->code
->outputs
[i
] = -1;
153 assert(OutputsWritten
& (1 << VERT_RESULT_HPOS
));
155 if (OutputsWritten
& (1 << VERT_RESULT_HPOS
)) {
156 c
->code
->outputs
[VERT_RESULT_HPOS
] = cur_reg
++;
159 if (OutputsWritten
& (1 << VERT_RESULT_PSIZ
)) {
160 c
->code
->outputs
[VERT_RESULT_PSIZ
] = cur_reg
++;
163 /* If we're writing back facing colors we need to send
164 * four colors to make front/back face colors selection work.
165 * If the vertex program doesn't write all 4 colors, lets
166 * pretend it does by skipping output index reg so the colors
167 * get written into appropriate output vectors.
169 if (OutputsWritten
& (1 << VERT_RESULT_COL0
)) {
170 c
->code
->outputs
[VERT_RESULT_COL0
] = cur_reg
++;
171 } else if (OutputsWritten
& (1 << VERT_RESULT_BFC0
) ||
172 OutputsWritten
& (1 << VERT_RESULT_BFC1
)) {
176 if (OutputsWritten
& (1 << VERT_RESULT_COL1
)) {
177 c
->code
->outputs
[VERT_RESULT_COL1
] = cur_reg
++;
178 } else if (OutputsWritten
& (1 << VERT_RESULT_BFC0
) ||
179 OutputsWritten
& (1 << VERT_RESULT_BFC1
)) {
183 if (OutputsWritten
& (1 << VERT_RESULT_BFC0
)) {
184 c
->code
->outputs
[VERT_RESULT_BFC0
] = cur_reg
++;
185 } else if (OutputsWritten
& (1 << VERT_RESULT_BFC1
)) {
189 if (OutputsWritten
& (1 << VERT_RESULT_BFC1
)) {
190 c
->code
->outputs
[VERT_RESULT_BFC1
] = cur_reg
++;
191 } else if (OutputsWritten
& (1 << VERT_RESULT_BFC0
)) {
195 for (i
= VERT_RESULT_TEX0
; i
<= VERT_RESULT_TEX7
; i
++) {
196 if (OutputsWritten
& (1 << i
)) {
197 c
->code
->outputs
[i
] = cur_reg
++;
201 if (OutputsWritten
& (1 << VERT_RESULT_FOGC
)) {
202 c
->code
->outputs
[VERT_RESULT_FOGC
] = cur_reg
++;
207 static struct r300_vertex_program
*build_program(GLcontext
*ctx
,
208 struct r300_vertex_program_key
*wanted_key
,
209 const struct gl_vertex_program
*mesa_vp
)
211 struct r300_vertex_program
*vp
;
212 struct r300_vertex_program_compiler compiler
;
214 vp
= _mesa_calloc(sizeof(*vp
));
215 vp
->Base
= (struct gl_vertex_program
*) _mesa_clone_program(ctx
, &mesa_vp
->Base
);
216 _mesa_memcpy(&vp
->key
, wanted_key
, sizeof(vp
->key
));
218 rc_init(&compiler
.Base
);
219 compiler
.Base
.Debug
= (RADEON_DEBUG
& DEBUG_VERTS
) ? GL_TRUE
: GL_FALSE
;
221 compiler
.code
= &vp
->code
;
222 compiler
.RequiredOutputs
= compute_required_outputs(vp
->Base
, vp
->key
.FpReads
);
223 compiler
.SetHwInputOutput
= &t_inputs_outputs
;
225 if (compiler
.Base
.Debug
) {
226 fprintf(stderr
, "Initial vertex program:\n");
227 _mesa_print_program(&vp
->Base
->Base
);
231 if (mesa_vp
->IsPositionInvariant
) {
232 _mesa_insert_mvp_code(ctx
, vp
->Base
);
235 rc_mesa_to_rc_program(&compiler
.Base
, &vp
->Base
->Base
);
237 rc_move_output(&compiler
.Base
, VERT_RESULT_PSIZ
, VERT_RESULT_PSIZ
, WRITEMASK_X
);
239 if (vp
->key
.WPosAttr
!= FRAG_ATTRIB_MAX
) {
240 rc_copy_output(&compiler
.Base
,
242 vp
->key
.WPosAttr
- FRAG_ATTRIB_TEX0
+ VERT_RESULT_TEX0
);
245 if (vp
->key
.FogAttr
!= FRAG_ATTRIB_MAX
) {
246 rc_move_output(&compiler
.Base
,
248 vp
->key
.FogAttr
- FRAG_ATTRIB_TEX0
+ VERT_RESULT_TEX0
, WRITEMASK_X
);
251 r3xx_compile_vertex_program(&compiler
);
252 vp
->error
= compiler
.Base
.Error
;
254 vp
->Base
->Base
.InputsRead
= vp
->code
.InputsRead
;
255 vp
->Base
->Base
.OutputsWritten
= vp
->code
.OutputsWritten
;
257 rc_destroy(&compiler
.Base
);
262 struct r300_vertex_program
* r300SelectAndTranslateVertexShader(GLcontext
*ctx
)
264 r300ContextPtr r300
= R300_CONTEXT(ctx
);
265 struct r300_vertex_program_key wanted_key
= { 0 };
266 struct r300_vertex_program_cont
*vpc
;
267 struct r300_vertex_program
*vp
;
269 vpc
= (struct r300_vertex_program_cont
*)ctx
->VertexProgram
._Current
;
270 wanted_key
.FpReads
= r300
->selected_fp
->InputsRead
;
271 wanted_key
.FogAttr
= r300
->selected_fp
->fog_attr
;
272 wanted_key
.WPosAttr
= r300
->selected_fp
->wpos_attr
;
274 for (vp
= vpc
->progs
; vp
; vp
= vp
->next
) {
275 if (_mesa_memcmp(&vp
->key
, &wanted_key
, sizeof(wanted_key
))
277 return r300
->selected_vp
= vp
;
281 vp
= build_program(ctx
, &wanted_key
, &vpc
->mesa_program
);
282 vp
->next
= vpc
->progs
;
285 return r300
->selected_vp
= vp
;
288 #define bump_vpu_count(ptr, new_count) do { \
289 drm_r300_cmd_header_t* _p=((drm_r300_cmd_header_t*)(ptr)); \
290 int _nc=(new_count)/4; \
292 if(_nc>_p->vpu.count)_p->vpu.count=_nc; \
295 static void r300EmitVertexProgram(r300ContextPtr r300
, int dest
, struct r300_vertex_program_code
*code
)
299 assert((code
->length
> 0) && (code
->length
% 4 == 0));
301 R300_STATECHANGE( r300
, vap_flush
);
303 switch ((dest
>> 8) & 0xf) {
305 R300_STATECHANGE(r300
, vpi
);
306 for (i
= 0; i
< code
->length
; i
++)
307 r300
->hw
.vpi
.cmd
[R300_VPI_INSTR_0
+ i
+ 4 * (dest
& 0xff)] = (code
->body
.d
[i
]);
308 bump_vpu_count(r300
->hw
.vpi
.cmd
, code
->length
+ 4 * (dest
& 0xff));
311 R300_STATECHANGE(r300
, vpp
);
312 for (i
= 0; i
< code
->length
; i
++)
313 r300
->hw
.vpp
.cmd
[R300_VPP_PARAM_0
+ i
+ 4 * (dest
& 0xff)] = (code
->body
.d
[i
]);
314 bump_vpu_count(r300
->hw
.vpp
.cmd
, code
->length
+ 4 * (dest
& 0xff));
317 R300_STATECHANGE(r300
, vps
);
318 for (i
= 0; i
< code
->length
; i
++)
319 r300
->hw
.vps
.cmd
[1 + i
+ 4 * (dest
& 0xff)] = (code
->body
.d
[i
]);
320 bump_vpu_count(r300
->hw
.vps
.cmd
, code
->length
+ 4 * (dest
& 0xff));
323 fprintf(stderr
, "%s:%s don't know how to handle dest %04x\n", __FILE__
, __FUNCTION__
, dest
);
328 void r300SetupVertexProgram(r300ContextPtr rmesa
)
330 GLcontext
*ctx
= rmesa
->radeon
.glCtx
;
331 struct r300_vertex_program
*prog
= rmesa
->selected_vp
;
335 /* Reset state, in case we don't use something */
336 ((drm_r300_cmd_header_t
*) rmesa
->hw
.vpp
.cmd
)->vpu
.count
= 0;
337 ((drm_r300_cmd_header_t
*) rmesa
->hw
.vpi
.cmd
)->vpu
.count
= 0;
338 ((drm_r300_cmd_header_t
*) rmesa
->hw
.vps
.cmd
)->vpu
.count
= 0;
340 R300_STATECHANGE(rmesa
, vap_flush
);
341 R300_STATECHANGE(rmesa
, vpp
);
342 param_count
= r300VertexProgUpdateParams(ctx
, prog
, (float *)&rmesa
->hw
.vpp
.cmd
[R300_VPP_PARAM_0
]);
343 bump_vpu_count(rmesa
->hw
.vpp
.cmd
, param_count
);
346 r300EmitVertexProgram(rmesa
, R300_PVS_CODE_START
, &(prog
->code
));
347 inst_count
= (prog
->code
.length
/ 4) - 1;
349 r300VapCntl(rmesa
, _mesa_bitcount(prog
->code
.InputsRead
),
350 _mesa_bitcount(prog
->code
.OutputsWritten
), prog
->code
.num_temporaries
);
352 R300_STATECHANGE(rmesa
, pvs
);
353 rmesa
->hw
.pvs
.cmd
[R300_PVS_CNTL_1
] = (0 << R300_PVS_FIRST_INST_SHIFT
) | (inst_count
<< R300_PVS_XYZW_VALID_INST_SHIFT
) |
354 (inst_count
<< R300_PVS_LAST_INST_SHIFT
);
356 rmesa
->hw
.pvs
.cmd
[R300_PVS_CNTL_2
] = (0 << R300_PVS_CONST_BASE_OFFSET_SHIFT
) | (param_count
<< R300_PVS_MAX_CONST_ADDR_SHIFT
);
357 rmesa
->hw
.pvs
.cmd
[R300_PVS_CNTL_3
] = (inst_count
<< R300_PVS_LAST_VTX_SRC_INST_SHIFT
);