1 /**************************************************************************
2 *
3 * Copyright 2007 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * 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, sub license, 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 portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * \file ffvertex_prog.c
30 *
31 * Create a vertex program to execute the current fixed function T&L pipeline.
32 * \author Keith Whitwell
33 */
34
35
36 #include "main/errors.h"
37 #include "util/glheader.h"
38 #include "main/mtypes.h"
39 #include "main/macros.h"
40 #include "main/enums.h"
41 #include "main/context.h"
42 #include "main/ffvertex_prog.h"
43 #include "program/program.h"
44 #include "program/prog_cache.h"
45 #include "program/prog_statevars.h"
46 #include "util/bitscan.h"
47
48 #include "state_tracker/st_program.h"
49 #include "state_tracker/st_nir.h"
50
51 #include "compiler/nir/nir_builder.h"
52 #include "compiler/nir/nir_builtin_builder.h"
53
54 /** Max of number of lights and texture coord units */
55 #define NUM_UNITS MAX2(MAX_TEXTURE_COORD_UNITS, MAX_LIGHTS)
56
57 struct state_key {
58 GLbitfield varying_vp_inputs;
59
60 unsigned fragprog_inputs_read:12;
61
62 unsigned light_color_material_mask:12;
63 unsigned light_global_enabled:1;
64 unsigned light_local_viewer:1;
65 unsigned light_twoside:1;
66 unsigned material_shininess_is_zero:1;
67 unsigned need_eye_coords:1;
68 unsigned normalize:1;
69 unsigned rescale_normals:1;
70
71 unsigned fog_distance_mode:2;
72 unsigned separate_specular:1;
73 unsigned point_attenuated:1;
74
75 struct {
76 unsigned char light_enabled:1;
77 unsigned char light_eyepos3_is_zero:1;
78 unsigned char light_spotcutoff_is_180:1;
79 unsigned char light_attenuated:1;
80 unsigned char texmat_enabled:1;
81 unsigned char coord_replace:1;
82 unsigned char texgen_enabled:1;
83 unsigned char texgen_mode0:4;
84 unsigned char texgen_mode1:4;
85 unsigned char texgen_mode2:4;
86 unsigned char texgen_mode3:4;
87 } unit[NUM_UNITS];
88 };
89
90
91 #define TXG_NONE 0
92 #define TXG_OBJ_LINEAR 1
93 #define TXG_EYE_LINEAR 2
94 #define TXG_SPHERE_MAP 3
95 #define TXG_REFLECTION_MAP 4
96 #define TXG_NORMAL_MAP 5
97
translate_texgen(GLboolean enabled,GLenum mode)98 static GLuint translate_texgen( GLboolean enabled, GLenum mode )
99 {
100 if (!enabled)
101 return TXG_NONE;
102
103 switch (mode) {
104 case GL_OBJECT_LINEAR: return TXG_OBJ_LINEAR;
105 case GL_EYE_LINEAR: return TXG_EYE_LINEAR;
106 case GL_SPHERE_MAP: return TXG_SPHERE_MAP;
107 case GL_REFLECTION_MAP_NV: return TXG_REFLECTION_MAP;
108 case GL_NORMAL_MAP_NV: return TXG_NORMAL_MAP;
109 default: return TXG_NONE;
110 }
111 }
112
113 #define FDM_EYE_RADIAL 0
114 #define FDM_EYE_PLANE 1
115 #define FDM_EYE_PLANE_ABS 2
116 #define FDM_FROM_ARRAY 3
117
translate_fog_distance_mode(GLenum source,GLenum mode)118 static GLuint translate_fog_distance_mode(GLenum source, GLenum mode)
119 {
120 if (source == GL_FRAGMENT_DEPTH_EXT) {
121 switch (mode) {
122 case GL_EYE_RADIAL_NV:
123 return FDM_EYE_RADIAL;
124 case GL_EYE_PLANE:
125 return FDM_EYE_PLANE;
126 default: /* shouldn't happen; fall through to a sensible default */
127 case GL_EYE_PLANE_ABSOLUTE_NV:
128 return FDM_EYE_PLANE_ABS;
129 }
130 } else {
131 return FDM_FROM_ARRAY;
132 }
133 }
134
check_active_shininess(struct gl_context * ctx,const struct state_key * key,GLuint side)135 static GLboolean check_active_shininess( struct gl_context *ctx,
136 const struct state_key *key,
137 GLuint side )
138 {
139 GLuint attr = MAT_ATTRIB_FRONT_SHININESS + side;
140
141 if ((key->varying_vp_inputs & VERT_BIT_COLOR0) &&
142 (key->light_color_material_mask & (1 << attr)))
143 return GL_TRUE;
144
145 if (key->varying_vp_inputs & VERT_BIT_MAT(attr))
146 return GL_TRUE;
147
148 if (ctx->Light.Material.Attrib[attr][0] != 0.0F)
149 return GL_TRUE;
150
151 return GL_FALSE;
152 }
153
154
make_state_key(struct gl_context * ctx,struct state_key * key)155 static void make_state_key( struct gl_context *ctx, struct state_key *key )
156 {
157 const struct gl_program *fp = ctx->FragmentProgram._Current;
158 GLbitfield mask;
159
160 memset(key, 0, sizeof(struct state_key));
161
162 if (_mesa_hw_select_enabled(ctx)) {
163 /* GL_SELECT mode only need position calculation.
164 * glBegin/End use VERT_BIT_SELECT_RESULT_OFFSET for multi name stack in one draw.
165 * glDrawArrays may also be called without user shader, fallback to FF one.
166 */
167 key->varying_vp_inputs = ctx->VertexProgram._VaryingInputs &
168 (VERT_BIT_POS | VERT_BIT_SELECT_RESULT_OFFSET);
169 return;
170 }
171
172 /* This now relies on texenvprogram.c being active:
173 */
174 assert(fp);
175
176 key->need_eye_coords = ctx->_NeedEyeCoords;
177
178 key->fragprog_inputs_read = fp->info.inputs_read;
179 key->varying_vp_inputs = ctx->VertexProgram._VaryingInputs;
180
181 if (ctx->RenderMode == GL_FEEDBACK) {
182 /* make sure the vertprog emits color and tex0 */
183 key->fragprog_inputs_read |= (VARYING_BIT_COL0 | VARYING_BIT_TEX0);
184 }
185
186 if (ctx->Light.Enabled) {
187 key->light_global_enabled = 1;
188
189 if (ctx->Light.Model.LocalViewer)
190 key->light_local_viewer = 1;
191
192 if (ctx->Light.Model.TwoSide)
193 key->light_twoside = 1;
194
195 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
196 key->separate_specular = 1;
197
198 if (ctx->Light.ColorMaterialEnabled) {
199 key->light_color_material_mask = ctx->Light._ColorMaterialBitmask;
200 }
201
202 mask = ctx->Light._EnabledLights;
203 while (mask) {
204 const int i = u_bit_scan(&mask);
205 struct gl_light_uniforms *lu = &ctx->Light.LightSource[i];
206
207 key->unit[i].light_enabled = 1;
208
209 if (lu->EyePosition[3] == 0.0F)
210 key->unit[i].light_eyepos3_is_zero = 1;
211
212 if (lu->SpotCutoff == 180.0F)
213 key->unit[i].light_spotcutoff_is_180 = 1;
214
215 if (lu->ConstantAttenuation != 1.0F ||
216 lu->LinearAttenuation != 0.0F ||
217 lu->QuadraticAttenuation != 0.0F)
218 key->unit[i].light_attenuated = 1;
219 }
220
221 if (check_active_shininess(ctx, key, 0)) {
222 key->material_shininess_is_zero = 0;
223 }
224 else if (key->light_twoside &&
225 check_active_shininess(ctx, key, 1)) {
226 key->material_shininess_is_zero = 0;
227 }
228 else {
229 key->material_shininess_is_zero = 1;
230 }
231 }
232
233 if (ctx->Transform.Normalize)
234 key->normalize = 1;
235
236 if (ctx->Transform.RescaleNormals)
237 key->rescale_normals = 1;
238
239 /* Only distinguish fog parameters if we actually need */
240 if (key->fragprog_inputs_read & VARYING_BIT_FOGC)
241 key->fog_distance_mode =
242 translate_fog_distance_mode(ctx->Fog.FogCoordinateSource,
243 ctx->Fog.FogDistanceMode);
244
245 if (ctx->Point._Attenuated)
246 key->point_attenuated = 1;
247
248 mask = ctx->Texture._EnabledCoordUnits | ctx->Texture._TexGenEnabled
249 | ctx->Texture._TexMatEnabled | ctx->Point.CoordReplace;
250 while (mask) {
251 const int i = u_bit_scan(&mask);
252 struct gl_fixedfunc_texture_unit *texUnit =
253 &ctx->Texture.FixedFuncUnit[i];
254
255 if (ctx->Point.PointSprite)
256 if (ctx->Point.CoordReplace & (1u << i))
257 key->unit[i].coord_replace = 1;
258
259 if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i))
260 key->unit[i].texmat_enabled = 1;
261
262 if (texUnit->TexGenEnabled) {
263 key->unit[i].texgen_enabled = 1;
264
265 key->unit[i].texgen_mode0 =
266 translate_texgen( texUnit->TexGenEnabled & (1<<0),
267 texUnit->GenS.Mode );
268 key->unit[i].texgen_mode1 =
269 translate_texgen( texUnit->TexGenEnabled & (1<<1),
270 texUnit->GenT.Mode );
271 key->unit[i].texgen_mode2 =
272 translate_texgen( texUnit->TexGenEnabled & (1<<2),
273 texUnit->GenR.Mode );
274 key->unit[i].texgen_mode3 =
275 translate_texgen( texUnit->TexGenEnabled & (1<<3),
276 texUnit->GenQ.Mode );
277 }
278 }
279 }
280
281 struct tnl_program {
282 const struct state_key *state;
283 struct gl_program_parameter_list *state_params;
284 GLboolean mvp_with_dp4;
285
286 nir_builder *b;
287
288 nir_def *eye_position;
289 nir_def *eye_position_z;
290 nir_def *eye_position_normalized;
291 nir_def *transformed_normal;
292
293 GLuint materials;
294 GLuint color_materials;
295 };
296
297 static nir_variable *
register_state_var(struct tnl_program * p,gl_state_index16 s0,gl_state_index16 s1,gl_state_index16 s2,gl_state_index16 s3,const struct glsl_type * type)298 register_state_var(struct tnl_program *p,
299 gl_state_index16 s0,
300 gl_state_index16 s1,
301 gl_state_index16 s2,
302 gl_state_index16 s3,
303 const struct glsl_type *type)
304 {
305 gl_state_index16 tokens[STATE_LENGTH];
306 tokens[0] = s0;
307 tokens[1] = s1;
308 tokens[2] = s2;
309 tokens[3] = s3;
310 nir_variable *var = nir_find_state_variable(p->b->shader, tokens);
311 if (var)
312 return var;
313
314 var = st_nir_state_variable_create(p->b->shader, type, tokens);
315 var->data.driver_location = _mesa_add_state_reference(p->state_params, tokens);
316
317 return var;
318 }
319
320 static nir_def *
load_state_var(struct tnl_program * p,gl_state_index16 s0,gl_state_index16 s1,gl_state_index16 s2,gl_state_index16 s3,const struct glsl_type * type)321 load_state_var(struct tnl_program *p,
322 gl_state_index16 s0,
323 gl_state_index16 s1,
324 gl_state_index16 s2,
325 gl_state_index16 s3,
326 const struct glsl_type *type)
327 {
328 nir_variable *var = register_state_var(p, s0, s1, s2, s3, type);
329 return nir_load_var(p->b, var);
330 }
331
332 static nir_def *
load_state_vec4(struct tnl_program * p,gl_state_index16 s0,gl_state_index16 s1,gl_state_index16 s2,gl_state_index16 s3)333 load_state_vec4(struct tnl_program *p,
334 gl_state_index16 s0,
335 gl_state_index16 s1,
336 gl_state_index16 s2,
337 gl_state_index16 s3)
338 {
339 return load_state_var(p, s0, s1, s2, s3, glsl_vec4_type());
340 }
341
342 static void
load_state_mat4(struct tnl_program * p,nir_def * out[4],gl_state_index state_index,unsigned tex_index)343 load_state_mat4(struct tnl_program *p, nir_def *out[4],
344 gl_state_index state_index, unsigned tex_index)
345 {
346 for (int i = 0; i < 4; ++i)
347 out[i] = load_state_vec4(p, state_index, tex_index, i, i);
348 }
349
350 static nir_def *
load_input(struct tnl_program * p,gl_vert_attrib attr,unsigned num_components)351 load_input(struct tnl_program *p, gl_vert_attrib attr, unsigned num_components)
352 {
353 if (p->state->varying_vp_inputs & VERT_BIT(attr)) {
354 return nir_load_input(p->b, num_components, 32, nir_imm_int(p->b, 0),
355 .io_semantics.location = attr);
356 } else {
357 return load_state_var(p, STATE_CURRENT_ATTRIB, attr, 0, 0,
358 glsl_vector_type(GLSL_TYPE_FLOAT, num_components));
359 }
360 }
361
362 static nir_def *
load_input_vec4(struct tnl_program * p,gl_vert_attrib attr)363 load_input_vec4(struct tnl_program *p, gl_vert_attrib attr)
364 {
365 return load_input(p, attr, 4);
366 }
367
368 static nir_variable *
register_output(struct tnl_program * p,gl_varying_slot slot,const struct glsl_type * type)369 register_output(struct tnl_program *p, gl_varying_slot slot,
370 const struct glsl_type *type)
371 {
372 nir_variable *var = nir_get_variable_with_location(p->b->shader, nir_var_shader_out,
373 slot, type);
374 p->b->shader->info.outputs_written |= BITFIELD64_BIT(slot);
375 return var;
376 }
377
378 static void
store_output_vec4_masked(struct tnl_program * p,gl_varying_slot slot,nir_def * value,unsigned writemask)379 store_output_vec4_masked(struct tnl_program *p, gl_varying_slot slot, nir_def *value,
380 unsigned writemask)
381 {
382 assert(writemask <= 0xf);
383 nir_store_output(p->b, value, nir_imm_int(p->b, 0),
384 .write_mask = writemask,
385 .io_semantics.location = slot);
386 }
387
388 static void
store_output_vec4(struct tnl_program * p,gl_varying_slot slot,nir_def * value)389 store_output_vec4(struct tnl_program *p, gl_varying_slot slot,
390 nir_def *value)
391 {
392 store_output_vec4_masked(p, slot, value, 0xf);
393 }
394
395 static void
store_output_float(struct tnl_program * p,gl_varying_slot slot,nir_def * value)396 store_output_float(struct tnl_program *p, gl_varying_slot slot,
397 nir_def *value)
398 {
399 store_output_vec4_masked(p, slot, value, 0x1);
400 }
401
402
403 static nir_def *
emit_matrix_transform_vec4(nir_builder * b,nir_def * mat[4],nir_def * src)404 emit_matrix_transform_vec4(nir_builder *b,
405 nir_def *mat[4],
406 nir_def *src)
407 {
408 return nir_vec4(b,
409 nir_fdot4(b, src, mat[0]),
410 nir_fdot4(b, src, mat[1]),
411 nir_fdot4(b, src, mat[2]),
412 nir_fdot4(b, src, mat[3]));
413 }
414
415 static nir_def *
emit_transpose_matrix_transform_vec4(nir_builder * b,nir_def * mat[4],nir_def * src)416 emit_transpose_matrix_transform_vec4(nir_builder *b,
417 nir_def *mat[4],
418 nir_def *src)
419 {
420 nir_def *result;
421 result = nir_fmul(b, nir_channel(b, src, 0), mat[0]);
422 result = nir_fmad(b, nir_channel(b, src, 1), mat[1], result);
423 result = nir_fmad(b, nir_channel(b, src, 2), mat[2], result);
424 result = nir_fmad(b, nir_channel(b, src, 3), mat[3], result);
425 return result;
426 }
427
428 static nir_def *
emit_matrix_transform_vec3(nir_builder * b,nir_def * mat[3],nir_def * src)429 emit_matrix_transform_vec3(nir_builder *b,
430 nir_def *mat[3],
431 nir_def *src)
432 {
433 return nir_vec3(b,
434 nir_fdot3(b, src, mat[0]),
435 nir_fdot3(b, src, mat[1]),
436 nir_fdot3(b, src, mat[2]));
437 }
438
439 static nir_def *
emit_normalize_vec3(nir_builder * b,nir_def * src)440 emit_normalize_vec3(nir_builder *b, nir_def *src)
441 {
442 nir_def *tmp = nir_frsq(b, nir_fdot3(b, src, src));
443 return nir_fmul(b, src, tmp);
444 }
445
446 static void
emit_passthrough(struct tnl_program * p,gl_vert_attrib attr,gl_varying_slot varying)447 emit_passthrough(struct tnl_program *p, gl_vert_attrib attr,
448 gl_varying_slot varying)
449 {
450 nir_def *val = load_input_vec4(p, attr);
451 store_output_vec4(p, varying, val);
452 }
453
454 static nir_def *
get_eye_position(struct tnl_program * p)455 get_eye_position(struct tnl_program *p)
456 {
457 if (!p->eye_position) {
458 nir_def *pos =
459 load_input_vec4(p, VERT_ATTRIB_POS);
460 if (p->mvp_with_dp4) {
461 nir_def *modelview[4];
462 load_state_mat4(p, modelview, STATE_MODELVIEW_MATRIX, 0);
463 p->eye_position =
464 emit_matrix_transform_vec4(p->b, modelview, pos);
465 } else {
466 nir_def *modelview[4];
467 load_state_mat4(p, modelview,
468 STATE_MODELVIEW_MATRIX_TRANSPOSE, 0);
469 p->eye_position =
470 emit_transpose_matrix_transform_vec4(p->b, modelview, pos);
471 }
472 }
473
474 return p->eye_position;
475 }
476
477 static nir_def *
get_eye_position_z(struct tnl_program * p)478 get_eye_position_z(struct tnl_program *p)
479 {
480 return nir_channel(p->b, get_eye_position(p), 2);
481 }
482
483 static nir_def *
get_eye_position_normalized(struct tnl_program * p)484 get_eye_position_normalized(struct tnl_program *p)
485 {
486 if (!p->eye_position_normalized) {
487 nir_def *eye = get_eye_position(p);
488 p->eye_position_normalized = emit_normalize_vec3(p->b, eye);
489 }
490
491 return p->eye_position_normalized;
492 }
493
494 static nir_def *
get_transformed_normal(struct tnl_program * p)495 get_transformed_normal(struct tnl_program *p)
496 {
497 if (!p->transformed_normal &&
498 !p->state->need_eye_coords &&
499 !p->state->normalize &&
500 !(p->state->need_eye_coords == p->state->rescale_normals)) {
501 p->transformed_normal = load_input(p, VERT_ATTRIB_NORMAL, 3);
502 } else if (!p->transformed_normal) {
503 nir_def *normal = load_input(p, VERT_ATTRIB_NORMAL, 3);
504
505 if (p->state->need_eye_coords) {
506 nir_def *mvinv[4];
507 load_state_mat4(p, mvinv, STATE_MODELVIEW_MATRIX_INVTRANS, 0);
508 normal = emit_matrix_transform_vec3(p->b, mvinv, normal);
509 }
510
511 /* Normalize/Rescale:
512 */
513 if (p->state->normalize)
514 normal = emit_normalize_vec3(p->b, normal);
515 else if (p->state->need_eye_coords == p->state->rescale_normals) {
516 nir_def *scale =
517 load_state_var(p, STATE_NORMAL_SCALE, 0, 0, 0,
518 glsl_float_type());
519 normal = nir_fmul(p->b, normal, scale);
520 }
521
522 p->transformed_normal = normal;
523 }
524
525 return p->transformed_normal;
526 }
527
material_attrib(GLuint side,GLuint property)528 static GLuint material_attrib( GLuint side, GLuint property )
529 {
530 switch (property) {
531 case STATE_AMBIENT:
532 return MAT_ATTRIB_FRONT_AMBIENT + side;
533 case STATE_DIFFUSE:
534 return MAT_ATTRIB_FRONT_DIFFUSE + side;
535 case STATE_SPECULAR:
536 return MAT_ATTRIB_FRONT_SPECULAR + side;
537 case STATE_EMISSION:
538 return MAT_ATTRIB_FRONT_EMISSION + side;
539 case STATE_SHININESS:
540 return MAT_ATTRIB_FRONT_SHININESS + side;
541 default:
542 unreachable("invalid value");
543 }
544 }
545
546
547 /**
548 * Get a bitmask of which material values vary on a per-vertex basis.
549 */
set_material_flags(struct tnl_program * p)550 static void set_material_flags( struct tnl_program *p )
551 {
552 p->color_materials = 0;
553 p->materials = 0;
554
555 if (p->state->varying_vp_inputs & VERT_BIT_COLOR0) {
556 p->materials =
557 p->color_materials = p->state->light_color_material_mask;
558 }
559
560 p->materials |= ((p->state->varying_vp_inputs & VERT_BIT_MAT_ALL)
561 >> VERT_ATTRIB_MAT(0));
562 }
563
564
565 static nir_def *
get_material(struct tnl_program * p,GLuint side,GLuint property)566 get_material(struct tnl_program *p, GLuint side,
567 GLuint property)
568 {
569 GLuint attrib = material_attrib(side, property);
570
571 if (p->color_materials & (1<<attrib))
572 return load_input_vec4(p, VERT_ATTRIB_COLOR0);
573 else if (p->materials & (1<<attrib)) {
574 /* Put material values in the GENERIC slots -- they are not used
575 * for anything in fixed function mode.
576 */
577 return load_input_vec4(p, VERT_ATTRIB_MAT(attrib));
578 } else {
579 return load_state_vec4(p, STATE_MATERIAL, attrib, 0, 0);
580 }
581 }
582
583 #define SCENE_COLOR_BITS(side) (( MAT_BIT_FRONT_EMISSION | \
584 MAT_BIT_FRONT_AMBIENT | \
585 MAT_BIT_FRONT_DIFFUSE) << (side))
586
587
588 /**
589 * Either return a precalculated constant value or emit code to
590 * calculate these values dynamically in the case where material calls
591 * are present between begin/end pairs.
592 *
593 * Probably want to shift this to the program compilation phase - if
594 * we always emitted the calculation here, a smart compiler could
595 * detect that it was constant (given a certain set of inputs), and
596 * lift it out of the main loop. That way the programs created here
597 * would be independent of the vertex_buffer details.
598 */
599 static nir_def *
get_scenecolor(struct tnl_program * p,GLuint side)600 get_scenecolor(struct tnl_program *p, GLuint side)
601 {
602 if (p->materials & SCENE_COLOR_BITS(side)) {
603 nir_def *lm_ambient =
604 load_state_vec4(p, STATE_LIGHTMODEL_AMBIENT, 0, 0, 0);
605 nir_def *material_emission =
606 get_material(p, side, STATE_EMISSION);
607 nir_def *material_ambient =
608 get_material(p, side, STATE_AMBIENT);
609 nir_def *material_diffuse =
610 get_material(p, side, STATE_DIFFUSE);
611
612 // rgb: material_emission + material_ambient * lm_ambient
613 // alpha: material_diffuse.a
614 return nir_vector_insert_imm(p->b, nir_fmad(p->b,
615 lm_ambient,
616 material_ambient,
617 material_emission),
618 nir_channel(p->b,
619 material_diffuse,
620 3),
621 3);
622 }
623 else
624 return load_state_vec4(p, STATE_LIGHTMODEL_SCENECOLOR, side, 0, 0);
625 }
626
627 static nir_def *
get_lightprod(struct tnl_program * p,GLuint light,GLuint side,GLuint property,bool * is_state_light)628 get_lightprod(struct tnl_program *p, GLuint light,
629 GLuint side, GLuint property, bool *is_state_light)
630 {
631 GLuint attrib = material_attrib(side, property);
632 if (p->materials & (1<<attrib)) {
633 *is_state_light = true;
634 return load_state_vec4(p, STATE_LIGHT, light, property, 0);
635 } else {
636 *is_state_light = false;
637 return load_state_vec4(p, STATE_LIGHTPROD, light, attrib, 0);
638 }
639 }
640
641
642 static nir_def *
calculate_light_attenuation(struct tnl_program * p,GLuint i,nir_def * VPpli,nir_def * dist)643 calculate_light_attenuation(struct tnl_program *p,
644 GLuint i,
645 nir_def *VPpli,
646 nir_def *dist)
647 {
648 nir_def *attenuation = NULL;
649 nir_def *att = NULL;
650
651 /* Calculate spot attenuation:
652 */
653 if (!p->state->unit[i].light_spotcutoff_is_180) {
654 nir_def *spot_dir_norm =
655 load_state_vec4(p, STATE_LIGHT_SPOT_DIR_NORMALIZED, i, 0, 0);
656 attenuation =
657 load_state_vec4(p, STATE_LIGHT, i, STATE_ATTENUATION, 0);
658
659 nir_def *spot = nir_fdot3(p->b, nir_fneg(p->b, VPpli),
660 spot_dir_norm);
661 nir_def *cmp = nir_flt(p->b, nir_channel(p->b, spot_dir_norm, 3),
662 spot);
663 spot = nir_fpow(p->b, spot, nir_channel(p->b, attenuation, 3));
664 att = nir_bcsel(p->b, cmp, spot, nir_imm_zero(p->b, 1, 32));
665 }
666
667 /* Calculate distance attenuation(See formula (2.4) at glspec 2.1 page 62):
668 *
669 * Skip the calucation when _dist_ is undefined(light_eyepos3_is_zero)
670 */
671 if (p->state->unit[i].light_attenuated && dist) {
672 if (!attenuation) {
673 attenuation = load_state_vec4(p, STATE_LIGHT, i,
674 STATE_ATTENUATION, 0);
675 }
676
677 /* dist is the reciprocal of ||VP|| used in the distance
678 * attenuation formula. So need to get the reciprocal of dist first
679 * before applying to the formula.
680 */
681 dist = nir_frcp(p->b, dist);
682
683 /* 1, d, d*d */
684 nir_def *tmp = nir_vec3(p->b,
685 nir_imm_float(p->b, 1.0f),
686 dist,
687 nir_fmul(p->b, dist, dist)
688 );
689 tmp = nir_frcp(p->b, nir_fdot3(p->b, tmp, attenuation));
690
691 if (!p->state->unit[i].light_spotcutoff_is_180)
692 return nir_fmul(p->b, tmp, att);
693 return tmp;
694 }
695
696 return att;
697 }
698
699 static nir_def *
emit_lit(nir_builder * b,nir_def * src)700 emit_lit(nir_builder *b,
701 nir_def *src)
702 {
703 nir_def *zero = nir_imm_zero(b, 1, 32);
704 nir_def *one = nir_imm_float(b, 1.0f);
705 nir_def *src_x = nir_channel(b, src, 0);
706 nir_def *src_y = nir_channel(b, src, 1);
707 nir_def *src_w = nir_channel(b, src, 3);
708
709 nir_def *wclamp = nir_fmax(b, nir_fmin(b, src_w,
710 nir_imm_float(b, 128.0f)),
711 nir_imm_float(b, -128.0f));
712 nir_def *pow = nir_fpow(b, nir_fmax(b, src_y, zero), wclamp);
713
714 return nir_vec4(b,
715 one,
716 nir_fmax(b, src_x, zero),
717 nir_bcsel(b,
718 nir_fge(b, zero, src_x),
719 zero,
720 pow),
721 one);
722 }
723
724 /**
725 * Compute:
726 * lit.y = MAX(0, dots.x)
727 * lit.z = SLT(0, dots.x)
728 */
729 static nir_def *
emit_degenerate_lit(nir_builder * b,nir_def * dots)730 emit_degenerate_lit(nir_builder *b,
731 nir_def *dots)
732 {
733 nir_def *id = nir_imm_vec4(b, 0.0f, 0.0f, 0.0f, 1.0f);
734
735 /* Note that lit.x & lit.w will not be examined. Note also that
736 * dots.xyzw == dots.xxxx.
737 */
738
739 nir_def *zero = nir_imm_zero(b, 1, 32);
740 nir_def *dots_x = nir_channel(b, dots, 0);
741 nir_def *tmp = nir_fmax(b, id, dots);
742 return nir_vector_insert_imm(b, tmp, nir_slt(b, zero, dots_x), 2);
743 }
744
745
746 /* Need to add some addtional parameters to allow lighting in object
747 * space - STATE_SPOT_DIRECTION and STATE_HALF_VECTOR implicitly assume eye
748 * space lighting.
749 */
build_lighting(struct tnl_program * p)750 static void build_lighting( struct tnl_program *p )
751 {
752 const GLboolean twoside = p->state->light_twoside;
753 const GLboolean separate = p->state->separate_specular;
754 GLuint nr_lights = 0;
755 nir_def *lit = NULL;
756 nir_def *dots = nir_imm_zero(p->b, 4, 32);
757 nir_def *normal = get_transformed_normal(p);
758 nir_def *_col0 = NULL, *_col1 = NULL;
759 nir_def *_bfc0 = NULL, *_bfc1 = NULL;
760 GLuint i;
761
762 /*
763 * NOTE:
764 * dots.x = dot(normal, VPpli)
765 * dots.y = dot(normal, halfAngle)
766 * dots.z = back.shininess
767 * dots.w = front.shininess
768 */
769
770 for (i = 0; i < MAX_LIGHTS; i++)
771 if (p->state->unit[i].light_enabled)
772 nr_lights++;
773
774 set_material_flags(p);
775
776 {
777 if (!p->state->material_shininess_is_zero) {
778 nir_def *shininess = get_material(p, 0, STATE_SHININESS);
779 nir_def *tmp = nir_channel(p->b, shininess, 0);
780 dots = nir_vector_insert_imm(p->b, dots, tmp, 3);
781 }
782
783 _col0 = get_scenecolor(p, 0);
784 if (separate)
785 _col1 = nir_imm_vec4(p->b, 0.0f, 0.0f, 0.0f, 1.0f);
786 }
787
788 if (twoside) {
789 if (!p->state->material_shininess_is_zero) {
790 /* Note that we negate the back-face specular exponent here.
791 * The negation will be un-done later in the back-face code below.
792 */
793 nir_def *shininess = get_material(p, 1, STATE_SHININESS);
794 nir_def *tmp = nir_channel(p->b, shininess, 0);
795 tmp = nir_fneg(p->b, tmp);
796 dots = nir_vector_insert_imm(p->b, dots, tmp, 2);
797 }
798
799 _bfc0 = get_scenecolor(p, 1);
800 if (separate)
801 _bfc1 = nir_imm_vec4(p->b, 0.0f, 0.0f, 0.0f, 1.0f);
802 }
803
804 /* If no lights, still need to emit the scenecolor.
805 */
806 store_output_vec4(p, VARYING_SLOT_COL0, _col0);
807
808 if (separate)
809 store_output_vec4(p, VARYING_SLOT_COL1, _col1);
810
811 if (twoside)
812 store_output_vec4(p, VARYING_SLOT_BFC0, _bfc0);
813
814 if (twoside && separate)
815 store_output_vec4(p, VARYING_SLOT_BFC1, _bfc1);
816
817 if (nr_lights == 0)
818 return;
819
820 /* Declare light products first to place them sequentially next to each
821 * other for optimal constant uploads.
822 */
823 nir_def *lightprod_front[MAX_LIGHTS][3];
824 nir_def *lightprod_back[MAX_LIGHTS][3];
825 bool lightprod_front_is_state_light[MAX_LIGHTS][3];
826 bool lightprod_back_is_state_light[MAX_LIGHTS][3];
827
828 for (i = 0; i < MAX_LIGHTS; i++) {
829 if (p->state->unit[i].light_enabled) {
830 lightprod_front[i][0] = get_lightprod(p, i, 0, STATE_AMBIENT,
831 &lightprod_front_is_state_light[i][0]);
832 if (twoside)
833 lightprod_back[i][0] = get_lightprod(p, i, 1, STATE_AMBIENT,
834 &lightprod_back_is_state_light[i][0]);
835
836 lightprod_front[i][1] = get_lightprod(p, i, 0, STATE_DIFFUSE,
837 &lightprod_front_is_state_light[i][1]);
838 if (twoside)
839 lightprod_back[i][1] = get_lightprod(p, i, 1, STATE_DIFFUSE,
840 &lightprod_back_is_state_light[i][1]);
841
842 lightprod_front[i][2] = get_lightprod(p, i, 0, STATE_SPECULAR,
843 &lightprod_front_is_state_light[i][2]);
844 if (twoside)
845 lightprod_back[i][2] = get_lightprod(p, i, 1, STATE_SPECULAR,
846 &lightprod_back_is_state_light[i][2]);
847 }
848 }
849
850 /* Add more variables now that we'll use later, so that they are nicely
851 * sorted in the parameter list.
852 */
853 for (i = 0; i < MAX_LIGHTS; i++) {
854 if (p->state->unit[i].light_enabled) {
855 if (p->state->unit[i].light_eyepos3_is_zero)
856 register_state_var(p, STATE_LIGHT_POSITION_NORMALIZED,
857 i, 0, 0,
858 glsl_vector_type(GLSL_TYPE_FLOAT, 3));
859 else
860 register_state_var(p, STATE_LIGHT_POSITION, i, 0, 0,
861 glsl_vec4_type());
862 }
863 }
864 for (i = 0; i < MAX_LIGHTS; i++) {
865 if (p->state->unit[i].light_enabled &&
866 (!p->state->unit[i].light_spotcutoff_is_180 ||
867 (p->state->unit[i].light_attenuated &&
868 !p->state->unit[i].light_eyepos3_is_zero)))
869 register_state_var(p, STATE_LIGHT, i, STATE_ATTENUATION, 0,
870 glsl_vec4_type());
871 }
872
873 for (i = 0; i < MAX_LIGHTS; i++) {
874 if (p->state->unit[i].light_enabled) {
875 nir_def *half = NULL;
876 nir_def *att = NULL, *VPpli = NULL;
877 nir_def *dist = NULL;
878
879 if (p->state->unit[i].light_eyepos3_is_zero) {
880 VPpli = load_state_var(p, STATE_LIGHT_POSITION_NORMALIZED,
881 i, 0, 0,
882 glsl_vector_type(GLSL_TYPE_FLOAT, 3));
883 } else {
884 nir_def *Ppli =
885 load_state_vec4(p, STATE_LIGHT_POSITION, i, 0, 0);
886
887 nir_def *V = get_eye_position(p);
888 VPpli = nir_fsub(p->b, Ppli, V);
889
890 /* Normalize VPpli. The dist value also used in
891 * attenuation below.
892 */
893 dist = nir_frsq(p->b, nir_fdot3(p->b, VPpli, VPpli));
894 VPpli = nir_fmul(p->b, VPpli, dist);
895 }
896
897 /* Calculate attenuation:
898 */
899 att = calculate_light_attenuation(p, i, VPpli, dist);
900
901 /* Calculate viewer direction, or use infinite viewer:
902 */
903 if (!p->state->material_shininess_is_zero) {
904 if (p->state->light_local_viewer) {
905 nir_def *eye_hat = get_eye_position_normalized(p);
906 half = emit_normalize_vec3(p->b,
907 nir_fsub(p->b, VPpli, eye_hat));
908 } else if (p->state->unit[i].light_eyepos3_is_zero) {
909 half =
910 load_state_var(p, STATE_LIGHT_HALF_VECTOR,
911 i, 0, 0,
912 glsl_vector_type(GLSL_TYPE_FLOAT, 3));
913 } else {
914 nir_def *tmp =
915 nir_fadd(p->b,
916 VPpli,
917 nir_imm_vec3(p->b, 0.0f, 0.0f, 1.0f));
918 half = emit_normalize_vec3(p->b, tmp);
919 }
920 }
921
922 /* Calculate dot products:
923 */
924 nir_def *dot = nir_fdot3(p->b, normal, VPpli);
925 if (p->state->material_shininess_is_zero) {
926 dots = nir_replicate(p->b, dot, 4);
927 } else {
928 dots = nir_vector_insert_imm(p->b, dots, dot, 0);
929 dot = nir_fdot3(p->b, normal, half);
930 dots = nir_vector_insert_imm(p->b, dots, dot, 1);
931 }
932
933 /* Front face lighting:
934 */
935 {
936 /* Transform STATE_LIGHT into STATE_LIGHTPROD if needed. This isn't done in
937 * get_lightprod to avoid using too many temps.
938 */
939 for (int j = 0; j < 3; j++) {
940 if (lightprod_front_is_state_light[i][j]) {
941 nir_def *material =
942 get_material(p, 0, STATE_AMBIENT + j);
943 lightprod_front[i][j] =
944 nir_fmul(p->b, lightprod_front[i][j], material);
945 }
946 }
947
948 nir_def *ambient = lightprod_front[i][0];
949 nir_def *diffuse = lightprod_front[i][1];
950 nir_def *specular = lightprod_front[i][2];
951
952 if (att) {
953 /* light is attenuated by distance */
954 lit = emit_lit(p->b, dots);
955 lit = nir_fmul(p->b, lit, att);
956 _col0 = nir_fmad(p->b, nir_channel(p->b, lit, 0), ambient, _col0);
957 } else if (!p->state->material_shininess_is_zero) {
958 /* there's a non-zero specular term */
959 lit = emit_lit(p->b, dots);
960 _col0 = nir_fadd(p->b, ambient, _col0);
961 } else {
962 /* no attenutation, no specular */
963 lit = emit_degenerate_lit(p->b, dots);
964 _col0 = nir_fadd(p->b, ambient, _col0);
965 }
966
967 _col0 = nir_fmad(p->b, nir_channel(p->b, lit, 1),
968 diffuse, _col0);
969 if (separate)
970 _col1 = nir_fmad(p->b, nir_channel(p->b, lit, 2),
971 specular, _col1);
972 else
973 _col0 = nir_fmad(p->b, nir_channel(p->b, lit, 2),
974 specular, _col0);
975 }
976 /* Back face lighting:
977 */
978 nir_def *old_dots = dots;
979 if (twoside) {
980 /* Transform STATE_LIGHT into STATE_LIGHTPROD if needed. This isn't done in
981 * get_lightprod to avoid using too many temps.
982 */
983 for (int j = 0; j < 3; j++) {
984 if (lightprod_back_is_state_light[i][j]) {
985 nir_def *material =
986 get_material(p, 1, STATE_AMBIENT + j);
987 lightprod_back[i][j] =
988 nir_fmul(p->b, lightprod_back[i][j], material);
989 }
990 }
991
992 nir_def *ambient = lightprod_back[i][0];
993 nir_def *diffuse = lightprod_back[i][1];
994 nir_def *specular = lightprod_back[i][2];
995
996 /* For the back face we need to negate the X and Y component
997 * dot products. dots.Z has the negated back-face specular
998 * exponent. We swizzle that into the W position. This
999 * negation makes the back-face specular term positive again.
1000 */
1001 unsigned swiz_xywz[] = {0, 1, 3, 2};
1002 nir_def *dots =
1003 nir_fneg(p->b, nir_swizzle(p->b, old_dots, swiz_xywz, 4));
1004
1005 if (att) {
1006 /* light is attenuated by distance */
1007 lit = emit_lit(p->b, dots);
1008 lit = nir_fmul(p->b, lit, att);
1009 _bfc0 = nir_fmad(p->b, nir_channel(p->b, lit, 0), ambient, _bfc0);
1010 } else if (!p->state->material_shininess_is_zero) {
1011 /* there's a non-zero specular term */
1012 lit = emit_lit(p->b, dots);
1013 _bfc0 = nir_fadd(p->b, ambient, _bfc0);
1014 } else {
1015 /* no attenutation, no specular */
1016 lit = emit_degenerate_lit(p->b, dots);
1017 _bfc0 = nir_fadd(p->b, ambient, _bfc0);
1018 }
1019
1020 _bfc0 = nir_fmad(p->b, nir_channel(p->b, lit, 1),
1021 diffuse, _bfc0);
1022 if (separate)
1023 _bfc1 = nir_fmad(p->b, nir_channel(p->b, lit, 2),
1024 specular, _bfc1);
1025 else
1026 _bfc0 = nir_fmad(p->b, nir_channel(p->b, lit, 2),
1027 specular, _bfc0);
1028 }
1029 }
1030 }
1031
1032 store_output_vec4_masked(p, VARYING_SLOT_COL0, _col0, 0x7);
1033 if (separate)
1034 store_output_vec4_masked(p, VARYING_SLOT_COL1, _col1, 0x7);
1035
1036 if (twoside) {
1037 store_output_vec4_masked(p, VARYING_SLOT_BFC0, _bfc0, 0x7);
1038 if (separate)
1039 store_output_vec4_masked(p, VARYING_SLOT_BFC1, _bfc1, 0x7);
1040 }
1041 }
1042
1043
build_fog(struct tnl_program * p)1044 static void build_fog( struct tnl_program *p )
1045 {
1046 nir_def *fog;
1047 switch (p->state->fog_distance_mode) {
1048 case FDM_EYE_RADIAL:
1049 /* Z = sqrt(Xe*Xe + Ye*Ye + Ze*Ze) */
1050 fog = nir_fast_length(p->b,
1051 nir_trim_vector(p->b, get_eye_position(p), 3));
1052 break;
1053 case FDM_EYE_PLANE: /* Z = Ze */
1054 fog = get_eye_position_z(p);
1055 break;
1056 case FDM_EYE_PLANE_ABS: /* Z = abs(Ze) */
1057 fog = nir_fabs(p->b, get_eye_position_z(p));
1058 break;
1059 case FDM_FROM_ARRAY:
1060 fog = load_input(p, VERT_ATTRIB_FOG, 1);
1061 break;
1062 default:
1063 unreachable("Bad fog mode in build_fog()");
1064 }
1065
1066 store_output_float(p, VARYING_SLOT_FOGC, fog);
1067 }
1068
1069
1070 static nir_def *
build_reflect_texgen(struct tnl_program * p)1071 build_reflect_texgen(struct tnl_program *p)
1072 {
1073 nir_def *normal = get_transformed_normal(p);
1074 nir_def *eye_hat = get_eye_position_normalized(p);
1075 /* n.u */
1076 nir_def *tmp = nir_fdot3(p->b, normal, eye_hat);
1077 /* 2n.u */
1078 tmp = nir_fadd(p->b, tmp, tmp);
1079 /* (-2n.u)n + u */
1080 return nir_fmad(p->b, nir_fneg(p->b, tmp), normal, eye_hat);
1081 }
1082
1083
1084 static nir_def *
build_sphere_texgen(struct tnl_program * p)1085 build_sphere_texgen(struct tnl_program *p)
1086 {
1087 nir_def *normal = get_transformed_normal(p);
1088 nir_def *eye_hat = get_eye_position_normalized(p);
1089
1090 /* Could share the above calculations, but it would be
1091 * a fairly odd state for someone to set (both sphere and
1092 * reflection active for different texture coordinate
1093 * components. Of course - if two texture units enable
1094 * reflect and/or sphere, things start to tilt in favour
1095 * of seperating this out:
1096 */
1097
1098 /* n.u */
1099 nir_def *tmp = nir_fdot3(p->b, normal, eye_hat);
1100 /* 2n.u */
1101 tmp = nir_fadd(p->b, tmp, tmp);
1102 /* (-2n.u)n + u */
1103 nir_def *r = nir_fmad(p->b, nir_fneg(p->b, tmp), normal, eye_hat);
1104 /* r + 0,0,1 */
1105 tmp = nir_fadd(p->b, r, nir_imm_vec4(p->b, 0.0f, 0.0f, 1.0f, 0.0f));
1106 /* rx^2 + ry^2 + (rz+1)^2 */
1107 tmp = nir_fdot3(p->b, tmp, tmp);
1108 /* 2/m */
1109 tmp = nir_frsq(p->b, tmp);
1110 /* 1/m */
1111 nir_def *inv_m = nir_fmul_imm(p->b, tmp, 0.5f);
1112 /* r/m + 1/2 */
1113 return nir_fmad(p->b, r, inv_m, nir_imm_float(p->b, 0.5f));
1114 }
1115
build_texture_transform(struct tnl_program * p)1116 static void build_texture_transform( struct tnl_program *p )
1117 {
1118 GLuint i, j;
1119
1120 for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
1121
1122 if (!(p->state->fragprog_inputs_read & VARYING_BIT_TEX(i)))
1123 continue;
1124
1125 if (p->state->unit[i].coord_replace)
1126 continue;
1127
1128 nir_def *texcoord;
1129 if (p->state->unit[i].texgen_enabled) {
1130 GLuint copy_mask = 0;
1131 GLuint sphere_mask = 0;
1132 GLuint reflect_mask = 0;
1133 GLuint normal_mask = 0;
1134 GLuint modes[4];
1135 nir_def *comps[4];
1136
1137 modes[0] = p->state->unit[i].texgen_mode0;
1138 modes[1] = p->state->unit[i].texgen_mode1;
1139 modes[2] = p->state->unit[i].texgen_mode2;
1140 modes[3] = p->state->unit[i].texgen_mode3;
1141
1142 for (j = 0; j < 4; j++) {
1143 switch (modes[j]) {
1144 case TXG_OBJ_LINEAR: {
1145 nir_def *obj = load_input_vec4(p, VERT_ATTRIB_POS);
1146 nir_def *plane =
1147 load_state_vec4(p, STATE_TEXGEN, i,
1148 STATE_TEXGEN_OBJECT_S + j, 0);
1149 comps[j] = nir_fdot4(p->b, obj, plane);
1150 break;
1151 }
1152 case TXG_EYE_LINEAR: {
1153 nir_def *eye = get_eye_position(p);
1154 nir_def *plane =
1155 load_state_vec4(p, STATE_TEXGEN, i,
1156 STATE_TEXGEN_EYE_S + j, 0);
1157 comps[j] = nir_fdot4(p->b, eye, plane);
1158 break;
1159 }
1160 case TXG_SPHERE_MAP:
1161 sphere_mask |= 1u << j;
1162 break;
1163 case TXG_REFLECTION_MAP:
1164 reflect_mask |= 1u << j;
1165 break;
1166 case TXG_NORMAL_MAP:
1167 normal_mask |= 1u << j;
1168 break;
1169 case TXG_NONE:
1170 copy_mask |= 1u << j;
1171 }
1172 }
1173
1174 if (sphere_mask) {
1175 nir_def *sphere = build_sphere_texgen(p);
1176 for (j = 0; j < 4; j++)
1177 if (sphere_mask & (1 << j))
1178 comps[j] = nir_channel(p->b, sphere, j);
1179 }
1180
1181 if (reflect_mask) {
1182 nir_def *reflect = build_reflect_texgen(p);
1183 for (j = 0; j < 4; j++)
1184 if (reflect_mask & (1 << j))
1185 comps[j] = nir_channel(p->b, reflect, j);
1186 }
1187
1188 if (normal_mask) {
1189 nir_def *normal = get_transformed_normal(p);
1190 for (j = 0; j < 4; j++)
1191 if (normal_mask & (1 << j))
1192 comps[j] = nir_channel(p->b, normal, j);
1193 }
1194
1195 if (copy_mask) {
1196 nir_def *in = load_input_vec4(p, VERT_ATTRIB_TEX0 + i);
1197 for (j = 0; j < 4; j++)
1198 if (copy_mask & (1 << j))
1199 comps[j] = nir_channel(p->b, in, j);
1200 }
1201
1202 texcoord = nir_vec(p->b, comps, 4);
1203 } else
1204 texcoord = load_input_vec4(p, VERT_ATTRIB_TEX0 + i);
1205
1206 if (p->state->unit[i].texmat_enabled) {
1207 nir_def *texmat[4];
1208 if (p->mvp_with_dp4) {
1209 load_state_mat4(p, texmat, STATE_TEXTURE_MATRIX, i);
1210 texcoord =
1211 emit_matrix_transform_vec4(p->b, texmat, texcoord);
1212 } else {
1213 load_state_mat4(p, texmat,
1214 STATE_TEXTURE_MATRIX_TRANSPOSE, i);
1215 texcoord =
1216 emit_transpose_matrix_transform_vec4(p->b, texmat,
1217 texcoord);
1218 }
1219 }
1220
1221 store_output_vec4(p, VARYING_SLOT_TEX0 + i, texcoord);
1222 }
1223 }
1224
1225
1226 /**
1227 * Point size attenuation computation.
1228 */
build_atten_pointsize(struct tnl_program * p)1229 static void build_atten_pointsize( struct tnl_program *p )
1230 {
1231 nir_def *eye = get_eye_position_z(p);
1232 nir_def *in_size =
1233 load_state_vec4(p, STATE_POINT_SIZE_CLAMPED, 0, 0, 0);
1234 nir_def *att =
1235 load_state_vec4(p, STATE_POINT_ATTENUATION, 0, 0, 0);
1236
1237 /* dist = |eyez| */
1238 nir_def *dist = nir_fabs(p->b, eye);
1239
1240 /* p1 + dist * (p2 + dist * p3); */
1241 nir_def *factor = nir_fmad(p->b, dist, nir_channel(p->b, att, 2),
1242 nir_channel(p->b, att, 1));
1243 factor = nir_fmad(p->b, dist, factor, nir_channel(p->b, att, 0));
1244
1245 /* 1 / sqrt(factor) */
1246 factor = nir_frsq(p->b, factor);
1247
1248 /* pointSize / sqrt(factor) */
1249 nir_def *size = nir_fmul(p->b, factor,
1250 nir_channel(p->b, in_size, 0));
1251
1252 #if 1
1253 /* this is a good place to clamp the point size since there's likely
1254 * no hardware registers to clamp point size at rasterization time.
1255 */
1256 size = nir_fclamp(p->b, size, nir_channel(p->b, in_size, 1),
1257 nir_channel(p->b, in_size, 2));
1258 #endif
1259
1260 store_output_float(p, VARYING_SLOT_PSIZ, size);
1261 }
1262
1263
1264 /**
1265 * Pass-though per-vertex point size, from user's point size array.
1266 */
build_array_pointsize(struct tnl_program * p)1267 static void build_array_pointsize( struct tnl_program *p )
1268 {
1269 nir_def *val = load_input(p, VERT_ATTRIB_POINT_SIZE, 1);
1270 store_output_float(p, VARYING_SLOT_PSIZ, val);
1271 }
1272
1273
build_tnl_program(struct tnl_program * p)1274 static void build_tnl_program( struct tnl_program *p )
1275 {
1276 /* Emit the program (except for the MVP transform, which is a separate pass) */
1277
1278 /* Lighting calculations:
1279 */
1280 if (p->state->fragprog_inputs_read &
1281 (VARYING_BIT_COL0 | VARYING_BIT_COL1)) {
1282 if (p->state->light_global_enabled)
1283 build_lighting(p);
1284 else {
1285 if (p->state->fragprog_inputs_read & VARYING_BIT_COL0)
1286 emit_passthrough(p, VERT_ATTRIB_COLOR0, VARYING_SLOT_COL0);
1287
1288 if (p->state->fragprog_inputs_read & VARYING_BIT_COL1)
1289 emit_passthrough(p, VERT_ATTRIB_COLOR1, VARYING_SLOT_COL1);
1290 }
1291 }
1292
1293 if (p->state->fragprog_inputs_read & VARYING_BIT_FOGC)
1294 build_fog(p);
1295
1296 if (p->state->fragprog_inputs_read & VARYING_BITS_TEX_ANY)
1297 build_texture_transform(p);
1298
1299 if (p->state->point_attenuated)
1300 build_atten_pointsize(p);
1301 else if (p->state->varying_vp_inputs & VERT_BIT_POINT_SIZE)
1302 build_array_pointsize(p);
1303
1304 if (p->state->varying_vp_inputs & VERT_BIT_SELECT_RESULT_OFFSET)
1305 emit_passthrough(p, VERT_ATTRIB_SELECT_RESULT_OFFSET,
1306 VARYING_SLOT_VAR0);
1307 }
1308
1309
1310 static nir_shader *
create_new_program(const struct state_key * key,struct gl_program * program,GLboolean mvp_with_dp4,const nir_shader_compiler_options * options)1311 create_new_program( const struct state_key *key,
1312 struct gl_program *program,
1313 GLboolean mvp_with_dp4,
1314 const nir_shader_compiler_options *options)
1315 {
1316 struct tnl_program p;
1317
1318 memset(&p, 0, sizeof(p));
1319 p.state = key;
1320 p.mvp_with_dp4 = mvp_with_dp4;
1321
1322 program->Parameters = _mesa_new_parameter_list();
1323 p.state_params = _mesa_new_parameter_list();
1324
1325 nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX,
1326 options,
1327 "ff-vs");
1328
1329 nir_shader *s = b.shader;
1330
1331 s->info.separate_shader = true;
1332 s->info.io_lowered = true;
1333
1334 p.b = &b;
1335
1336 build_tnl_program( &p );
1337
1338 nir_validate_shader(b.shader, "after generating ff-vertex shader");
1339
1340 /* Emit the MVP position transformation */
1341 NIR_PASS(_, b.shader, st_nir_lower_position_invariant, mvp_with_dp4, p.state_params);
1342
1343 _mesa_add_separate_state_parameters(program, p.state_params);
1344 _mesa_free_parameter_list(p.state_params);
1345
1346 return s;
1347 }
1348
1349
1350 /**
1351 * Return a vertex program which implements the current fixed-function
1352 * transform/lighting/texgen operations.
1353 */
1354 struct gl_program *
_mesa_get_fixed_func_vertex_program(struct gl_context * ctx)1355 _mesa_get_fixed_func_vertex_program(struct gl_context *ctx)
1356 {
1357 struct gl_program *prog;
1358 struct state_key key;
1359
1360 /* We only update ctx->VertexProgram._VaryingInputs when in VP_MODE_FF _VPMode */
1361 assert(VP_MODE_FF == ctx->VertexProgram._VPMode);
1362
1363 /* Grab all the relevant state and put it in a single structure:
1364 */
1365 make_state_key(ctx, &key);
1366
1367 /* Look for an already-prepared program for this state:
1368 */
1369 prog = _mesa_search_program_cache(ctx->VertexProgram.Cache, &key,
1370 sizeof(key));
1371
1372 if (!prog) {
1373 /* OK, we'll have to build a new one */
1374 if (0)
1375 printf("Build new TNL program\n");
1376
1377 prog = ctx->Driver.NewProgram(ctx, MESA_SHADER_VERTEX, 0, false);
1378 if (!prog)
1379 return NULL;
1380
1381 const struct nir_shader_compiler_options *options =
1382 st_get_nir_compiler_options(ctx->st, MESA_SHADER_VERTEX);
1383
1384 nir_shader *s =
1385 create_new_program( &key, prog,
1386 ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].OptimizeForAOS,
1387 options);
1388
1389 prog->state.type = PIPE_SHADER_IR_NIR;
1390 prog->nir = s;
1391
1392 st_program_string_notify(ctx, GL_VERTEX_PROGRAM_ARB, prog);
1393
1394 _mesa_program_cache_insert(ctx, ctx->VertexProgram.Cache, &key,
1395 sizeof(key), prog);
1396 }
1397
1398 return prog;
1399 }
1400