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,const struct glsl_type * type)351 load_input(struct tnl_program *p, gl_vert_attrib attr,
352 const struct glsl_type *type)
353 {
354 if (p->state->varying_vp_inputs & VERT_BIT(attr)) {
355 nir_variable *var = nir_get_variable_with_location(p->b->shader, nir_var_shader_in,
356 attr, type);
357 p->b->shader->info.inputs_read |= (uint64_t)VERT_BIT(attr);
358 return nir_load_var(p->b, var);
359 } else
360 return load_state_var(p, STATE_CURRENT_ATTRIB, attr, 0, 0, type);
361 }
362
363 static nir_def *
load_input_vec4(struct tnl_program * p,gl_vert_attrib attr)364 load_input_vec4(struct tnl_program *p, gl_vert_attrib attr)
365 {
366 return load_input(p, attr, glsl_vec4_type());
367 }
368
369 static nir_variable *
register_output(struct tnl_program * p,gl_varying_slot slot,const struct glsl_type * type)370 register_output(struct tnl_program *p, gl_varying_slot slot,
371 const struct glsl_type *type)
372 {
373 nir_variable *var = nir_get_variable_with_location(p->b->shader, nir_var_shader_out,
374 slot, type);
375 p->b->shader->info.outputs_written |= BITFIELD64_BIT(slot);
376 return var;
377 }
378
379 static void
store_output_vec4_masked(struct tnl_program * p,gl_varying_slot slot,nir_def * value,unsigned mask)380 store_output_vec4_masked(struct tnl_program *p, gl_varying_slot slot,
381 nir_def *value, unsigned mask)
382 {
383 assert(mask <= 0xf);
384 nir_variable *var = register_output(p, slot, glsl_vec4_type());
385 nir_store_var(p->b, var, value, mask);
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 nir_variable *var = register_output(p, slot, glsl_float_type());
400 nir_store_var(p->b, var, value, 0x1);
401 }
402
403
404 static nir_def *
emit_matrix_transform_vec4(nir_builder * b,nir_def * mat[4],nir_def * src)405 emit_matrix_transform_vec4(nir_builder *b,
406 nir_def *mat[4],
407 nir_def *src)
408 {
409 return nir_vec4(b,
410 nir_fdot4(b, src, mat[0]),
411 nir_fdot4(b, src, mat[1]),
412 nir_fdot4(b, src, mat[2]),
413 nir_fdot4(b, src, mat[3]));
414 }
415
416 static nir_def *
emit_transpose_matrix_transform_vec4(nir_builder * b,nir_def * mat[4],nir_def * src)417 emit_transpose_matrix_transform_vec4(nir_builder *b,
418 nir_def *mat[4],
419 nir_def *src)
420 {
421 nir_def *result;
422 result = nir_fmul(b, nir_channel(b, src, 0), mat[0]);
423 result = nir_fmad(b, nir_channel(b, src, 1), mat[1], result);
424 result = nir_fmad(b, nir_channel(b, src, 2), mat[2], result);
425 result = nir_fmad(b, nir_channel(b, src, 3), mat[3], result);
426 return result;
427 }
428
429 static nir_def *
emit_matrix_transform_vec3(nir_builder * b,nir_def * mat[3],nir_def * src)430 emit_matrix_transform_vec3(nir_builder *b,
431 nir_def *mat[3],
432 nir_def *src)
433 {
434 return nir_vec3(b,
435 nir_fdot3(b, src, mat[0]),
436 nir_fdot3(b, src, mat[1]),
437 nir_fdot3(b, src, mat[2]));
438 }
439
440 static nir_def *
emit_normalize_vec3(nir_builder * b,nir_def * src)441 emit_normalize_vec3(nir_builder *b, nir_def *src)
442 {
443 nir_def *tmp = nir_frsq(b, nir_fdot3(b, src, src));
444 return nir_fmul(b, src, tmp);
445 }
446
447 static void
emit_passthrough(struct tnl_program * p,gl_vert_attrib attr,gl_varying_slot varying)448 emit_passthrough(struct tnl_program *p, gl_vert_attrib attr,
449 gl_varying_slot varying)
450 {
451 nir_def *val = load_input_vec4(p, attr);
452 store_output_vec4(p, varying, val);
453 }
454
455 static nir_def *
get_eye_position(struct tnl_program * p)456 get_eye_position(struct tnl_program *p)
457 {
458 if (!p->eye_position) {
459 nir_def *pos =
460 load_input_vec4(p, VERT_ATTRIB_POS);
461 if (p->mvp_with_dp4) {
462 nir_def *modelview[4];
463 load_state_mat4(p, modelview, STATE_MODELVIEW_MATRIX, 0);
464 p->eye_position =
465 emit_matrix_transform_vec4(p->b, modelview, pos);
466 } else {
467 nir_def *modelview[4];
468 load_state_mat4(p, modelview,
469 STATE_MODELVIEW_MATRIX_TRANSPOSE, 0);
470 p->eye_position =
471 emit_transpose_matrix_transform_vec4(p->b, modelview, pos);
472 }
473 }
474
475 return p->eye_position;
476 }
477
478 static nir_def *
get_eye_position_z(struct tnl_program * p)479 get_eye_position_z(struct tnl_program *p)
480 {
481 return nir_channel(p->b, get_eye_position(p), 2);
482 }
483
484 static nir_def *
get_eye_position_normalized(struct tnl_program * p)485 get_eye_position_normalized(struct tnl_program *p)
486 {
487 if (!p->eye_position_normalized) {
488 nir_def *eye = get_eye_position(p);
489 p->eye_position_normalized = emit_normalize_vec3(p->b, eye);
490 }
491
492 return p->eye_position_normalized;
493 }
494
495 static nir_def *
get_transformed_normal(struct tnl_program * p)496 get_transformed_normal(struct tnl_program *p)
497 {
498 if (!p->transformed_normal &&
499 !p->state->need_eye_coords &&
500 !p->state->normalize &&
501 !(p->state->need_eye_coords == p->state->rescale_normals)) {
502 p->transformed_normal =
503 load_input(p, VERT_ATTRIB_NORMAL,
504 glsl_vector_type(GLSL_TYPE_FLOAT, 3));
505 } else if (!p->transformed_normal) {
506 nir_def *normal =
507 load_input(p, VERT_ATTRIB_NORMAL,
508 glsl_vector_type(GLSL_TYPE_FLOAT, 3));
509
510 if (p->state->need_eye_coords) {
511 nir_def *mvinv[4];
512 load_state_mat4(p, mvinv, STATE_MODELVIEW_MATRIX_INVTRANS, 0);
513 normal = emit_matrix_transform_vec3(p->b, mvinv, normal);
514 }
515
516 /* Normalize/Rescale:
517 */
518 if (p->state->normalize)
519 normal = emit_normalize_vec3(p->b, normal);
520 else if (p->state->need_eye_coords == p->state->rescale_normals) {
521 nir_def *scale =
522 load_state_var(p, STATE_NORMAL_SCALE, 0, 0, 0,
523 glsl_float_type());
524 normal = nir_fmul(p->b, normal, scale);
525 }
526
527 p->transformed_normal = normal;
528 }
529
530 return p->transformed_normal;
531 }
532
material_attrib(GLuint side,GLuint property)533 static GLuint material_attrib( GLuint side, GLuint property )
534 {
535 switch (property) {
536 case STATE_AMBIENT:
537 return MAT_ATTRIB_FRONT_AMBIENT + side;
538 case STATE_DIFFUSE:
539 return MAT_ATTRIB_FRONT_DIFFUSE + side;
540 case STATE_SPECULAR:
541 return MAT_ATTRIB_FRONT_SPECULAR + side;
542 case STATE_EMISSION:
543 return MAT_ATTRIB_FRONT_EMISSION + side;
544 case STATE_SHININESS:
545 return MAT_ATTRIB_FRONT_SHININESS + side;
546 default:
547 unreachable("invalid value");
548 }
549 }
550
551
552 /**
553 * Get a bitmask of which material values vary on a per-vertex basis.
554 */
set_material_flags(struct tnl_program * p)555 static void set_material_flags( struct tnl_program *p )
556 {
557 p->color_materials = 0;
558 p->materials = 0;
559
560 if (p->state->varying_vp_inputs & VERT_BIT_COLOR0) {
561 p->materials =
562 p->color_materials = p->state->light_color_material_mask;
563 }
564
565 p->materials |= ((p->state->varying_vp_inputs & VERT_BIT_MAT_ALL)
566 >> VERT_ATTRIB_MAT(0));
567 }
568
569
570 static nir_def *
get_material(struct tnl_program * p,GLuint side,GLuint property)571 get_material(struct tnl_program *p, GLuint side,
572 GLuint property)
573 {
574 GLuint attrib = material_attrib(side, property);
575
576 if (p->color_materials & (1<<attrib))
577 return load_input_vec4(p, VERT_ATTRIB_COLOR0);
578 else if (p->materials & (1<<attrib)) {
579 /* Put material values in the GENERIC slots -- they are not used
580 * for anything in fixed function mode.
581 */
582 return load_input_vec4(p, VERT_ATTRIB_MAT(attrib));
583 } else {
584 return load_state_vec4(p, STATE_MATERIAL, attrib, 0, 0);
585 }
586 }
587
588 #define SCENE_COLOR_BITS(side) (( MAT_BIT_FRONT_EMISSION | \
589 MAT_BIT_FRONT_AMBIENT | \
590 MAT_BIT_FRONT_DIFFUSE) << (side))
591
592
593 /**
594 * Either return a precalculated constant value or emit code to
595 * calculate these values dynamically in the case where material calls
596 * are present between begin/end pairs.
597 *
598 * Probably want to shift this to the program compilation phase - if
599 * we always emitted the calculation here, a smart compiler could
600 * detect that it was constant (given a certain set of inputs), and
601 * lift it out of the main loop. That way the programs created here
602 * would be independent of the vertex_buffer details.
603 */
604 static nir_def *
get_scenecolor(struct tnl_program * p,GLuint side)605 get_scenecolor(struct tnl_program *p, GLuint side)
606 {
607 if (p->materials & SCENE_COLOR_BITS(side)) {
608 nir_def *lm_ambient =
609 load_state_vec4(p, STATE_LIGHTMODEL_AMBIENT, 0, 0, 0);
610 nir_def *material_emission =
611 get_material(p, side, STATE_EMISSION);
612 nir_def *material_ambient =
613 get_material(p, side, STATE_AMBIENT);
614 nir_def *material_diffuse =
615 get_material(p, side, STATE_DIFFUSE);
616
617 // rgb: material_emission + material_ambient * lm_ambient
618 // alpha: material_diffuse.a
619 return nir_vector_insert_imm(p->b, nir_fmad(p->b,
620 lm_ambient,
621 material_ambient,
622 material_emission),
623 nir_channel(p->b,
624 material_diffuse,
625 3),
626 3);
627 }
628 else
629 return load_state_vec4(p, STATE_LIGHTMODEL_SCENECOLOR, side, 0, 0);
630 }
631
632 static nir_def *
get_lightprod(struct tnl_program * p,GLuint light,GLuint side,GLuint property,bool * is_state_light)633 get_lightprod(struct tnl_program *p, GLuint light,
634 GLuint side, GLuint property, bool *is_state_light)
635 {
636 GLuint attrib = material_attrib(side, property);
637 if (p->materials & (1<<attrib)) {
638 *is_state_light = true;
639 return load_state_vec4(p, STATE_LIGHT, light, property, 0);
640 } else {
641 *is_state_light = false;
642 return load_state_vec4(p, STATE_LIGHTPROD, light, attrib, 0);
643 }
644 }
645
646
647 static nir_def *
calculate_light_attenuation(struct tnl_program * p,GLuint i,nir_def * VPpli,nir_def * dist)648 calculate_light_attenuation(struct tnl_program *p,
649 GLuint i,
650 nir_def *VPpli,
651 nir_def *dist)
652 {
653 nir_def *attenuation = NULL;
654 nir_def *att = NULL;
655
656 /* Calculate spot attenuation:
657 */
658 if (!p->state->unit[i].light_spotcutoff_is_180) {
659 nir_def *spot_dir_norm =
660 load_state_vec4(p, STATE_LIGHT_SPOT_DIR_NORMALIZED, i, 0, 0);
661 attenuation =
662 load_state_vec4(p, STATE_LIGHT, i, STATE_ATTENUATION, 0);
663
664 nir_def *spot = nir_fdot3(p->b, nir_fneg(p->b, VPpli),
665 spot_dir_norm);
666 nir_def *cmp = nir_flt(p->b, nir_channel(p->b, spot_dir_norm, 3),
667 spot);
668 spot = nir_fpow(p->b, spot, nir_channel(p->b, attenuation, 3));
669 att = nir_bcsel(p->b, cmp, spot, nir_imm_zero(p->b, 1, 32));
670 }
671
672 /* Calculate distance attenuation(See formula (2.4) at glspec 2.1 page 62):
673 *
674 * Skip the calucation when _dist_ is undefined(light_eyepos3_is_zero)
675 */
676 if (p->state->unit[i].light_attenuated && dist) {
677 if (!attenuation) {
678 attenuation = load_state_vec4(p, STATE_LIGHT, i,
679 STATE_ATTENUATION, 0);
680 }
681
682 /* dist is the reciprocal of ||VP|| used in the distance
683 * attenuation formula. So need to get the reciprocal of dist first
684 * before applying to the formula.
685 */
686 dist = nir_frcp(p->b, dist);
687
688 /* 1, d, d*d */
689 nir_def *tmp = nir_vec3(p->b,
690 nir_imm_float(p->b, 1.0f),
691 dist,
692 nir_fmul(p->b, dist, dist)
693 );
694 tmp = nir_frcp(p->b, nir_fdot3(p->b, tmp, attenuation));
695
696 if (!p->state->unit[i].light_spotcutoff_is_180)
697 return nir_fmul(p->b, tmp, att);
698 return tmp;
699 }
700
701 return att;
702 }
703
704 static nir_def *
emit_lit(nir_builder * b,nir_def * src)705 emit_lit(nir_builder *b,
706 nir_def *src)
707 {
708 nir_def *zero = nir_imm_zero(b, 1, 32);
709 nir_def *one = nir_imm_float(b, 1.0f);
710 nir_def *src_x = nir_channel(b, src, 0);
711 nir_def *src_y = nir_channel(b, src, 1);
712 nir_def *src_w = nir_channel(b, src, 3);
713
714 nir_def *wclamp = nir_fmax(b, nir_fmin(b, src_w,
715 nir_imm_float(b, 128.0f)),
716 nir_imm_float(b, -128.0f));
717 nir_def *pow = nir_fpow(b, nir_fmax(b, src_y, zero), wclamp);
718
719 return nir_vec4(b,
720 one,
721 nir_fmax(b, src_x, zero),
722 nir_bcsel(b,
723 nir_fge(b, zero, src_x),
724 zero,
725 pow),
726 one);
727 }
728
729 /**
730 * Compute:
731 * lit.y = MAX(0, dots.x)
732 * lit.z = SLT(0, dots.x)
733 */
734 static nir_def *
emit_degenerate_lit(nir_builder * b,nir_def * dots)735 emit_degenerate_lit(nir_builder *b,
736 nir_def *dots)
737 {
738 nir_def *id = nir_imm_vec4(b, 0.0f, 0.0f, 0.0f, 1.0f);
739
740 /* Note that lit.x & lit.w will not be examined. Note also that
741 * dots.xyzw == dots.xxxx.
742 */
743
744 nir_def *zero = nir_imm_zero(b, 1, 32);
745 nir_def *dots_x = nir_channel(b, dots, 0);
746 nir_def *tmp = nir_fmax(b, id, dots);
747 return nir_vector_insert_imm(b, tmp, nir_slt(b, zero, dots_x), 2);
748 }
749
750
751 /* Need to add some addtional parameters to allow lighting in object
752 * space - STATE_SPOT_DIRECTION and STATE_HALF_VECTOR implicitly assume eye
753 * space lighting.
754 */
build_lighting(struct tnl_program * p)755 static void build_lighting( struct tnl_program *p )
756 {
757 const GLboolean twoside = p->state->light_twoside;
758 const GLboolean separate = p->state->separate_specular;
759 GLuint nr_lights = 0;
760 nir_def *lit = NULL;
761 nir_def *dots = nir_imm_zero(p->b, 4, 32);
762 nir_def *normal = get_transformed_normal(p);
763 nir_def *_col0 = NULL, *_col1 = NULL;
764 nir_def *_bfc0 = NULL, *_bfc1 = NULL;
765 GLuint i;
766
767 /*
768 * NOTE:
769 * dots.x = dot(normal, VPpli)
770 * dots.y = dot(normal, halfAngle)
771 * dots.z = back.shininess
772 * dots.w = front.shininess
773 */
774
775 for (i = 0; i < MAX_LIGHTS; i++)
776 if (p->state->unit[i].light_enabled)
777 nr_lights++;
778
779 set_material_flags(p);
780
781 {
782 if (!p->state->material_shininess_is_zero) {
783 nir_def *shininess = get_material(p, 0, STATE_SHININESS);
784 nir_def *tmp = nir_channel(p->b, shininess, 0);
785 dots = nir_vector_insert_imm(p->b, dots, tmp, 3);
786 }
787
788 _col0 = get_scenecolor(p, 0);
789 if (separate)
790 _col1 = nir_imm_vec4(p->b, 0.0f, 0.0f, 0.0f, 1.0f);
791 }
792
793 if (twoside) {
794 if (!p->state->material_shininess_is_zero) {
795 /* Note that we negate the back-face specular exponent here.
796 * The negation will be un-done later in the back-face code below.
797 */
798 nir_def *shininess = get_material(p, 1, STATE_SHININESS);
799 nir_def *tmp = nir_channel(p->b, shininess, 0);
800 tmp = nir_fneg(p->b, tmp);
801 dots = nir_vector_insert_imm(p->b, dots, tmp, 2);
802 }
803
804 _bfc0 = get_scenecolor(p, 1);
805 if (separate)
806 _bfc1 = nir_imm_vec4(p->b, 0.0f, 0.0f, 0.0f, 1.0f);
807 }
808
809 /* If no lights, still need to emit the scenecolor.
810 */
811 store_output_vec4(p, VARYING_SLOT_COL0, _col0);
812
813 if (separate)
814 store_output_vec4(p, VARYING_SLOT_COL1, _col1);
815
816 if (twoside)
817 store_output_vec4(p, VARYING_SLOT_BFC0, _bfc0);
818
819 if (twoside && separate)
820 store_output_vec4(p, VARYING_SLOT_BFC1, _bfc1);
821
822 if (nr_lights == 0)
823 return;
824
825 /* Declare light products first to place them sequentially next to each
826 * other for optimal constant uploads.
827 */
828 nir_def *lightprod_front[MAX_LIGHTS][3];
829 nir_def *lightprod_back[MAX_LIGHTS][3];
830 bool lightprod_front_is_state_light[MAX_LIGHTS][3];
831 bool lightprod_back_is_state_light[MAX_LIGHTS][3];
832
833 for (i = 0; i < MAX_LIGHTS; i++) {
834 if (p->state->unit[i].light_enabled) {
835 lightprod_front[i][0] = get_lightprod(p, i, 0, STATE_AMBIENT,
836 &lightprod_front_is_state_light[i][0]);
837 if (twoside)
838 lightprod_back[i][0] = get_lightprod(p, i, 1, STATE_AMBIENT,
839 &lightprod_back_is_state_light[i][0]);
840
841 lightprod_front[i][1] = get_lightprod(p, i, 0, STATE_DIFFUSE,
842 &lightprod_front_is_state_light[i][1]);
843 if (twoside)
844 lightprod_back[i][1] = get_lightprod(p, i, 1, STATE_DIFFUSE,
845 &lightprod_back_is_state_light[i][1]);
846
847 lightprod_front[i][2] = get_lightprod(p, i, 0, STATE_SPECULAR,
848 &lightprod_front_is_state_light[i][2]);
849 if (twoside)
850 lightprod_back[i][2] = get_lightprod(p, i, 1, STATE_SPECULAR,
851 &lightprod_back_is_state_light[i][2]);
852 }
853 }
854
855 /* Add more variables now that we'll use later, so that they are nicely
856 * sorted in the parameter list.
857 */
858 for (i = 0; i < MAX_LIGHTS; i++) {
859 if (p->state->unit[i].light_enabled) {
860 if (p->state->unit[i].light_eyepos3_is_zero)
861 register_state_var(p, STATE_LIGHT_POSITION_NORMALIZED,
862 i, 0, 0,
863 glsl_vector_type(GLSL_TYPE_FLOAT, 3));
864 else
865 register_state_var(p, STATE_LIGHT_POSITION, i, 0, 0,
866 glsl_vec4_type());
867 }
868 }
869 for (i = 0; i < MAX_LIGHTS; i++) {
870 if (p->state->unit[i].light_enabled &&
871 (!p->state->unit[i].light_spotcutoff_is_180 ||
872 (p->state->unit[i].light_attenuated &&
873 !p->state->unit[i].light_eyepos3_is_zero)))
874 register_state_var(p, STATE_LIGHT, i, STATE_ATTENUATION, 0,
875 glsl_vec4_type());
876 }
877
878 for (i = 0; i < MAX_LIGHTS; i++) {
879 if (p->state->unit[i].light_enabled) {
880 nir_def *half = NULL;
881 nir_def *att = NULL, *VPpli = NULL;
882 nir_def *dist = NULL;
883
884 if (p->state->unit[i].light_eyepos3_is_zero) {
885 VPpli = load_state_var(p, STATE_LIGHT_POSITION_NORMALIZED,
886 i, 0, 0,
887 glsl_vector_type(GLSL_TYPE_FLOAT, 3));
888 } else {
889 nir_def *Ppli =
890 load_state_vec4(p, STATE_LIGHT_POSITION, i, 0, 0);
891
892 nir_def *V = get_eye_position(p);
893 VPpli = nir_fsub(p->b, Ppli, V);
894
895 /* Normalize VPpli. The dist value also used in
896 * attenuation below.
897 */
898 dist = nir_frsq(p->b, nir_fdot3(p->b, VPpli, VPpli));
899 VPpli = nir_fmul(p->b, VPpli, dist);
900 }
901
902 /* Calculate attenuation:
903 */
904 att = calculate_light_attenuation(p, i, VPpli, dist);
905
906 /* Calculate viewer direction, or use infinite viewer:
907 */
908 if (!p->state->material_shininess_is_zero) {
909 if (p->state->light_local_viewer) {
910 nir_def *eye_hat = get_eye_position_normalized(p);
911 half = emit_normalize_vec3(p->b,
912 nir_fsub(p->b, VPpli, eye_hat));
913 } else if (p->state->unit[i].light_eyepos3_is_zero) {
914 half =
915 load_state_var(p, STATE_LIGHT_HALF_VECTOR,
916 i, 0, 0,
917 glsl_vector_type(GLSL_TYPE_FLOAT, 3));
918 } else {
919 nir_def *tmp =
920 nir_fadd(p->b,
921 VPpli,
922 nir_imm_vec3(p->b, 0.0f, 0.0f, 1.0f));
923 half = emit_normalize_vec3(p->b, tmp);
924 }
925 }
926
927 /* Calculate dot products:
928 */
929 nir_def *dot = nir_fdot3(p->b, normal, VPpli);
930 if (p->state->material_shininess_is_zero) {
931 dots = nir_replicate(p->b, dot, 4);
932 } else {
933 dots = nir_vector_insert_imm(p->b, dots, dot, 0);
934 dot = nir_fdot3(p->b, normal, half);
935 dots = nir_vector_insert_imm(p->b, dots, dot, 1);
936 }
937
938 /* Front face lighting:
939 */
940 {
941 /* Transform STATE_LIGHT into STATE_LIGHTPROD if needed. This isn't done in
942 * get_lightprod to avoid using too many temps.
943 */
944 for (int j = 0; j < 3; j++) {
945 if (lightprod_front_is_state_light[i][j]) {
946 nir_def *material =
947 get_material(p, 0, STATE_AMBIENT + j);
948 lightprod_front[i][j] =
949 nir_fmul(p->b, lightprod_front[i][j], material);
950 }
951 }
952
953 nir_def *ambient = lightprod_front[i][0];
954 nir_def *diffuse = lightprod_front[i][1];
955 nir_def *specular = lightprod_front[i][2];
956
957 if (att) {
958 /* light is attenuated by distance */
959 lit = emit_lit(p->b, dots);
960 lit = nir_fmul(p->b, lit, att);
961 _col0 = nir_fmad(p->b, nir_channel(p->b, lit, 0), ambient, _col0);
962 } else if (!p->state->material_shininess_is_zero) {
963 /* there's a non-zero specular term */
964 lit = emit_lit(p->b, dots);
965 _col0 = nir_fadd(p->b, ambient, _col0);
966 } else {
967 /* no attenutation, no specular */
968 lit = emit_degenerate_lit(p->b, dots);
969 _col0 = nir_fadd(p->b, ambient, _col0);
970 }
971
972 _col0 = nir_fmad(p->b, nir_channel(p->b, lit, 1),
973 diffuse, _col0);
974 if (separate)
975 _col1 = nir_fmad(p->b, nir_channel(p->b, lit, 2),
976 specular, _col1);
977 else
978 _col0 = nir_fmad(p->b, nir_channel(p->b, lit, 2),
979 specular, _col0);
980 }
981 /* Back face lighting:
982 */
983 nir_def *old_dots = dots;
984 if (twoside) {
985 /* Transform STATE_LIGHT into STATE_LIGHTPROD if needed. This isn't done in
986 * get_lightprod to avoid using too many temps.
987 */
988 for (int j = 0; j < 3; j++) {
989 if (lightprod_back_is_state_light[i][j]) {
990 nir_def *material =
991 get_material(p, 1, STATE_AMBIENT + j);
992 lightprod_back[i][j] =
993 nir_fmul(p->b, lightprod_back[i][j], material);
994 }
995 }
996
997 nir_def *ambient = lightprod_back[i][0];
998 nir_def *diffuse = lightprod_back[i][1];
999 nir_def *specular = lightprod_back[i][2];
1000
1001 /* For the back face we need to negate the X and Y component
1002 * dot products. dots.Z has the negated back-face specular
1003 * exponent. We swizzle that into the W position. This
1004 * negation makes the back-face specular term positive again.
1005 */
1006 unsigned swiz_xywz[] = {0, 1, 3, 2};
1007 nir_def *dots =
1008 nir_fneg(p->b, nir_swizzle(p->b, old_dots, swiz_xywz, 4));
1009
1010 if (att) {
1011 /* light is attenuated by distance */
1012 lit = emit_lit(p->b, dots);
1013 lit = nir_fmul(p->b, lit, att);
1014 _bfc0 = nir_fmad(p->b, nir_channel(p->b, lit, 0), ambient, _bfc0);
1015 } else if (!p->state->material_shininess_is_zero) {
1016 /* there's a non-zero specular term */
1017 lit = emit_lit(p->b, dots);
1018 _bfc0 = nir_fadd(p->b, ambient, _bfc0);
1019 } else {
1020 /* no attenutation, no specular */
1021 lit = emit_degenerate_lit(p->b, dots);
1022 _bfc0 = nir_fadd(p->b, ambient, _bfc0);
1023 }
1024
1025 _bfc0 = nir_fmad(p->b, nir_channel(p->b, lit, 1),
1026 diffuse, _bfc0);
1027 if (separate)
1028 _bfc1 = nir_fmad(p->b, nir_channel(p->b, lit, 2),
1029 specular, _bfc1);
1030 else
1031 _bfc0 = nir_fmad(p->b, nir_channel(p->b, lit, 2),
1032 specular, _bfc0);
1033 }
1034 }
1035 }
1036
1037 store_output_vec4_masked(p, VARYING_SLOT_COL0, _col0, 0x7);
1038 if (separate)
1039 store_output_vec4_masked(p, VARYING_SLOT_COL1, _col1, 0x7);
1040
1041 if (twoside) {
1042 store_output_vec4_masked(p, VARYING_SLOT_BFC0, _bfc0, 0x7);
1043 if (separate)
1044 store_output_vec4_masked(p, VARYING_SLOT_BFC1, _bfc1, 0x7);
1045 }
1046 }
1047
1048
build_fog(struct tnl_program * p)1049 static void build_fog( struct tnl_program *p )
1050 {
1051 nir_def *fog;
1052 switch (p->state->fog_distance_mode) {
1053 case FDM_EYE_RADIAL:
1054 /* Z = sqrt(Xe*Xe + Ye*Ye + Ze*Ze) */
1055 fog = nir_fast_length(p->b,
1056 nir_trim_vector(p->b, get_eye_position(p), 3));
1057 break;
1058 case FDM_EYE_PLANE: /* Z = Ze */
1059 fog = get_eye_position_z(p);
1060 break;
1061 case FDM_EYE_PLANE_ABS: /* Z = abs(Ze) */
1062 fog = nir_fabs(p->b, get_eye_position_z(p));
1063 break;
1064 case FDM_FROM_ARRAY:
1065 fog = load_input(p, VERT_ATTRIB_FOG, glsl_float_type());
1066 break;
1067 default:
1068 unreachable("Bad fog mode in build_fog()");
1069 }
1070
1071 store_output_float(p, VARYING_SLOT_FOGC, fog);
1072 }
1073
1074
1075 static nir_def *
build_reflect_texgen(struct tnl_program * p)1076 build_reflect_texgen(struct tnl_program *p)
1077 {
1078 nir_def *normal = get_transformed_normal(p);
1079 nir_def *eye_hat = get_eye_position_normalized(p);
1080 /* n.u */
1081 nir_def *tmp = nir_fdot3(p->b, normal, eye_hat);
1082 /* 2n.u */
1083 tmp = nir_fadd(p->b, tmp, tmp);
1084 /* (-2n.u)n + u */
1085 return nir_fmad(p->b, nir_fneg(p->b, tmp), normal, eye_hat);
1086 }
1087
1088
1089 static nir_def *
build_sphere_texgen(struct tnl_program * p)1090 build_sphere_texgen(struct tnl_program *p)
1091 {
1092 nir_def *normal = get_transformed_normal(p);
1093 nir_def *eye_hat = get_eye_position_normalized(p);
1094
1095 /* Could share the above calculations, but it would be
1096 * a fairly odd state for someone to set (both sphere and
1097 * reflection active for different texture coordinate
1098 * components. Of course - if two texture units enable
1099 * reflect and/or sphere, things start to tilt in favour
1100 * of seperating this out:
1101 */
1102
1103 /* n.u */
1104 nir_def *tmp = nir_fdot3(p->b, normal, eye_hat);
1105 /* 2n.u */
1106 tmp = nir_fadd(p->b, tmp, tmp);
1107 /* (-2n.u)n + u */
1108 nir_def *r = nir_fmad(p->b, nir_fneg(p->b, tmp), normal, eye_hat);
1109 /* r + 0,0,1 */
1110 tmp = nir_fadd(p->b, r, nir_imm_vec4(p->b, 0.0f, 0.0f, 1.0f, 0.0f));
1111 /* rx^2 + ry^2 + (rz+1)^2 */
1112 tmp = nir_fdot3(p->b, tmp, tmp);
1113 /* 2/m */
1114 tmp = nir_frsq(p->b, tmp);
1115 /* 1/m */
1116 nir_def *inv_m = nir_fmul_imm(p->b, tmp, 0.5f);
1117 /* r/m + 1/2 */
1118 return nir_fmad(p->b, r, inv_m, nir_imm_float(p->b, 0.5f));
1119 }
1120
build_texture_transform(struct tnl_program * p)1121 static void build_texture_transform( struct tnl_program *p )
1122 {
1123 GLuint i, j;
1124
1125 for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
1126
1127 if (!(p->state->fragprog_inputs_read & VARYING_BIT_TEX(i)))
1128 continue;
1129
1130 if (p->state->unit[i].coord_replace)
1131 continue;
1132
1133 nir_def *texcoord;
1134 if (p->state->unit[i].texgen_enabled) {
1135 GLuint copy_mask = 0;
1136 GLuint sphere_mask = 0;
1137 GLuint reflect_mask = 0;
1138 GLuint normal_mask = 0;
1139 GLuint modes[4];
1140 nir_def *comps[4];
1141
1142 modes[0] = p->state->unit[i].texgen_mode0;
1143 modes[1] = p->state->unit[i].texgen_mode1;
1144 modes[2] = p->state->unit[i].texgen_mode2;
1145 modes[3] = p->state->unit[i].texgen_mode3;
1146
1147 for (j = 0; j < 4; j++) {
1148 switch (modes[j]) {
1149 case TXG_OBJ_LINEAR: {
1150 nir_def *obj = load_input_vec4(p, VERT_ATTRIB_POS);
1151 nir_def *plane =
1152 load_state_vec4(p, STATE_TEXGEN, i,
1153 STATE_TEXGEN_OBJECT_S + j, 0);
1154 comps[j] = nir_fdot4(p->b, obj, plane);
1155 break;
1156 }
1157 case TXG_EYE_LINEAR: {
1158 nir_def *eye = get_eye_position(p);
1159 nir_def *plane =
1160 load_state_vec4(p, STATE_TEXGEN, i,
1161 STATE_TEXGEN_EYE_S + j, 0);
1162 comps[j] = nir_fdot4(p->b, eye, plane);
1163 break;
1164 }
1165 case TXG_SPHERE_MAP:
1166 sphere_mask |= 1u << j;
1167 break;
1168 case TXG_REFLECTION_MAP:
1169 reflect_mask |= 1u << j;
1170 break;
1171 case TXG_NORMAL_MAP:
1172 normal_mask |= 1u << j;
1173 break;
1174 case TXG_NONE:
1175 copy_mask |= 1u << j;
1176 }
1177 }
1178
1179 if (sphere_mask) {
1180 nir_def *sphere = build_sphere_texgen(p);
1181 for (j = 0; j < 4; j++)
1182 if (sphere_mask & (1 << j))
1183 comps[j] = nir_channel(p->b, sphere, j);
1184 }
1185
1186 if (reflect_mask) {
1187 nir_def *reflect = build_reflect_texgen(p);
1188 for (j = 0; j < 4; j++)
1189 if (reflect_mask & (1 << j))
1190 comps[j] = nir_channel(p->b, reflect, j);
1191 }
1192
1193 if (normal_mask) {
1194 nir_def *normal = get_transformed_normal(p);
1195 for (j = 0; j < 4; j++)
1196 if (normal_mask & (1 << j))
1197 comps[j] = nir_channel(p->b, normal, j);
1198 }
1199
1200 if (copy_mask) {
1201 nir_def *in = load_input_vec4(p, VERT_ATTRIB_TEX0 + i);
1202 for (j = 0; j < 4; j++)
1203 if (copy_mask & (1 << j))
1204 comps[j] = nir_channel(p->b, in, j);
1205 }
1206
1207 texcoord = nir_vec(p->b, comps, 4);
1208 } else
1209 texcoord = load_input_vec4(p, VERT_ATTRIB_TEX0 + i);
1210
1211 if (p->state->unit[i].texmat_enabled) {
1212 nir_def *texmat[4];
1213 if (p->mvp_with_dp4) {
1214 load_state_mat4(p, texmat, STATE_TEXTURE_MATRIX, i);
1215 texcoord =
1216 emit_matrix_transform_vec4(p->b, texmat, texcoord);
1217 } else {
1218 load_state_mat4(p, texmat,
1219 STATE_TEXTURE_MATRIX_TRANSPOSE, i);
1220 texcoord =
1221 emit_transpose_matrix_transform_vec4(p->b, texmat,
1222 texcoord);
1223 }
1224 }
1225
1226 store_output_vec4(p, VARYING_SLOT_TEX0 + i, texcoord);
1227 }
1228 }
1229
1230
1231 /**
1232 * Point size attenuation computation.
1233 */
build_atten_pointsize(struct tnl_program * p)1234 static void build_atten_pointsize( struct tnl_program *p )
1235 {
1236 nir_def *eye = get_eye_position_z(p);
1237 nir_def *in_size =
1238 load_state_vec4(p, STATE_POINT_SIZE_CLAMPED, 0, 0, 0);
1239 nir_def *att =
1240 load_state_vec4(p, STATE_POINT_ATTENUATION, 0, 0, 0);
1241
1242 /* dist = |eyez| */
1243 nir_def *dist = nir_fabs(p->b, eye);
1244
1245 /* p1 + dist * (p2 + dist * p3); */
1246 nir_def *factor = nir_fmad(p->b, dist, nir_channel(p->b, att, 2),
1247 nir_channel(p->b, att, 1));
1248 factor = nir_fmad(p->b, dist, factor, nir_channel(p->b, att, 0));
1249
1250 /* 1 / sqrt(factor) */
1251 factor = nir_frsq(p->b, factor);
1252
1253 /* pointSize / sqrt(factor) */
1254 nir_def *size = nir_fmul(p->b, factor,
1255 nir_channel(p->b, in_size, 0));
1256
1257 #if 1
1258 /* this is a good place to clamp the point size since there's likely
1259 * no hardware registers to clamp point size at rasterization time.
1260 */
1261 size = nir_fclamp(p->b, size, nir_channel(p->b, in_size, 1),
1262 nir_channel(p->b, in_size, 2));
1263 #endif
1264
1265 store_output_float(p, VARYING_SLOT_PSIZ, size);
1266 }
1267
1268
1269 /**
1270 * Pass-though per-vertex point size, from user's point size array.
1271 */
build_array_pointsize(struct tnl_program * p)1272 static void build_array_pointsize( struct tnl_program *p )
1273 {
1274 nir_def *val = load_input(p, VERT_ATTRIB_POINT_SIZE,
1275 glsl_float_type());
1276 store_output_float(p, VARYING_SLOT_PSIZ, val);
1277 }
1278
1279
build_tnl_program(struct tnl_program * p)1280 static void build_tnl_program( struct tnl_program *p )
1281 {
1282 /* Emit the program (except for the MVP transform, which is a separate pass) */
1283
1284 /* Lighting calculations:
1285 */
1286 if (p->state->fragprog_inputs_read &
1287 (VARYING_BIT_COL0 | VARYING_BIT_COL1)) {
1288 if (p->state->light_global_enabled)
1289 build_lighting(p);
1290 else {
1291 if (p->state->fragprog_inputs_read & VARYING_BIT_COL0)
1292 emit_passthrough(p, VERT_ATTRIB_COLOR0, VARYING_SLOT_COL0);
1293
1294 if (p->state->fragprog_inputs_read & VARYING_BIT_COL1)
1295 emit_passthrough(p, VERT_ATTRIB_COLOR1, VARYING_SLOT_COL1);
1296 }
1297 }
1298
1299 if (p->state->fragprog_inputs_read & VARYING_BIT_FOGC)
1300 build_fog(p);
1301
1302 if (p->state->fragprog_inputs_read & VARYING_BITS_TEX_ANY)
1303 build_texture_transform(p);
1304
1305 if (p->state->point_attenuated)
1306 build_atten_pointsize(p);
1307 else if (p->state->varying_vp_inputs & VERT_BIT_POINT_SIZE)
1308 build_array_pointsize(p);
1309
1310 if (p->state->varying_vp_inputs & VERT_BIT_SELECT_RESULT_OFFSET)
1311 emit_passthrough(p, VERT_ATTRIB_SELECT_RESULT_OFFSET,
1312 VARYING_SLOT_VAR0);
1313 }
1314
1315
1316 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)1317 create_new_program( const struct state_key *key,
1318 struct gl_program *program,
1319 GLboolean mvp_with_dp4,
1320 const nir_shader_compiler_options *options)
1321 {
1322 struct tnl_program p;
1323
1324 memset(&p, 0, sizeof(p));
1325 p.state = key;
1326 p.mvp_with_dp4 = mvp_with_dp4;
1327
1328 program->Parameters = _mesa_new_parameter_list();
1329 p.state_params = _mesa_new_parameter_list();
1330
1331 nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX,
1332 options,
1333 "ff-vs");
1334
1335 nir_shader *s = b.shader;
1336
1337 s->info.separate_shader = true;
1338
1339 p.b = &b;
1340
1341 build_tnl_program( &p );
1342
1343 nir_validate_shader(b.shader, "after generating ff-vertex shader");
1344
1345 /* Emit the MVP position transformation */
1346 NIR_PASS(_, b.shader, st_nir_lower_position_invariant, mvp_with_dp4, p.state_params);
1347
1348 _mesa_add_separate_state_parameters(program, p.state_params);
1349 _mesa_free_parameter_list(p.state_params);
1350
1351 return s;
1352 }
1353
1354
1355 /**
1356 * Return a vertex program which implements the current fixed-function
1357 * transform/lighting/texgen operations.
1358 */
1359 struct gl_program *
_mesa_get_fixed_func_vertex_program(struct gl_context * ctx)1360 _mesa_get_fixed_func_vertex_program(struct gl_context *ctx)
1361 {
1362 struct gl_program *prog;
1363 struct state_key key;
1364
1365 /* We only update ctx->VertexProgram._VaryingInputs when in VP_MODE_FF _VPMode */
1366 assert(VP_MODE_FF == ctx->VertexProgram._VPMode);
1367
1368 /* Grab all the relevant state and put it in a single structure:
1369 */
1370 make_state_key(ctx, &key);
1371
1372 /* Look for an already-prepared program for this state:
1373 */
1374 prog = _mesa_search_program_cache(ctx->VertexProgram.Cache, &key,
1375 sizeof(key));
1376
1377 if (!prog) {
1378 /* OK, we'll have to build a new one */
1379 if (0)
1380 printf("Build new TNL program\n");
1381
1382 prog = ctx->Driver.NewProgram(ctx, MESA_SHADER_VERTEX, 0, false);
1383 if (!prog)
1384 return NULL;
1385
1386 const struct nir_shader_compiler_options *options =
1387 st_get_nir_compiler_options(ctx->st, MESA_SHADER_VERTEX);
1388
1389 nir_shader *s =
1390 create_new_program( &key, prog,
1391 ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].OptimizeForAOS,
1392 options);
1393
1394 prog->state.type = PIPE_SHADER_IR_NIR;
1395 prog->nir = s;
1396
1397 st_program_string_notify(ctx, GL_VERTEX_PROGRAM_ARB, prog);
1398
1399 _mesa_program_cache_insert(ctx, ctx->VertexProgram.Cache, &key,
1400 sizeof(key), prog);
1401 }
1402
1403 return prog;
1404 }
1405