Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / nouveau / nv10_state_tnl.c
1 /*
2  * Copyright (C) 2009-2010 Francisco Jerez.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26
27 #include "nouveau_driver.h"
28 #include "nouveau_context.h"
29 #include "nouveau_gldefs.h"
30 #include "nouveau_util.h"
31 #include "nv10_3d.xml.h"
32 #include "nv10_driver.h"
33
34 void
35 nv10_emit_clip_plane(struct gl_context *ctx, int emit)
36 {
37 }
38
39 static inline unsigned
40 get_material_bitmask(unsigned m)
41 {
42         unsigned ret = 0;
43
44         if (m & MAT_BIT_FRONT_EMISSION)
45                 ret |= NV10_3D_COLOR_MATERIAL_EMISSION;
46         if (m & MAT_BIT_FRONT_AMBIENT)
47                 ret |= NV10_3D_COLOR_MATERIAL_AMBIENT;
48         if (m & MAT_BIT_FRONT_DIFFUSE)
49                 ret |= NV10_3D_COLOR_MATERIAL_DIFFUSE;
50         if (m & MAT_BIT_FRONT_SPECULAR)
51                 ret |= NV10_3D_COLOR_MATERIAL_SPECULAR;
52
53         return ret;
54 }
55
56 void
57 nv10_emit_color_material(struct gl_context *ctx, int emit)
58 {
59         struct nouveau_channel *chan = context_chan(ctx);
60         struct nouveau_grobj *celsius = context_eng3d(ctx);
61         unsigned mask = get_material_bitmask(ctx->Light.ColorMaterialBitmask);
62
63         BEGIN_RING(chan, celsius, NV10_3D_COLOR_MATERIAL, 1);
64         OUT_RING(chan, ctx->Light.ColorMaterialEnabled ? mask : 0);
65 }
66
67 static unsigned
68 get_fog_mode(unsigned mode)
69 {
70         switch (mode) {
71         case GL_LINEAR:
72                 return NV10_3D_FOG_MODE_LINEAR;
73         case GL_EXP:
74                 return NV10_3D_FOG_MODE_EXP;
75         case GL_EXP2:
76                 return NV10_3D_FOG_MODE_EXP2;
77         default:
78                 assert(0);
79         }
80 }
81
82 static unsigned
83 get_fog_source(unsigned source)
84 {
85         switch (source) {
86         case GL_FOG_COORDINATE_EXT:
87                 return NV10_3D_FOG_COORD_FOG;
88         case GL_FRAGMENT_DEPTH_EXT:
89                 return NV10_3D_FOG_COORD_DIST_ORTHOGONAL_ABS;
90         default:
91                 assert(0);
92         }
93 }
94
95 void
96 nv10_get_fog_coeff(struct gl_context *ctx, float k[3])
97 {
98         struct gl_fog_attrib *f = &ctx->Fog;
99
100         switch (f->Mode) {
101         case GL_LINEAR:
102                 k[0] = 2 + f->Start / (f->End - f->Start);
103                 k[1] = -1 / (f->End - f->Start);
104                 break;
105
106         case GL_EXP:
107                 k[0] = 1.5;
108                 k[1] = -0.09 * f->Density;
109                 break;
110
111         case GL_EXP2:
112                 k[0] = 1.5;
113                 k[1] = -0.21 * f->Density;
114                 break;
115
116         default:
117                 assert(0);
118         }
119
120         k[2] = 0;
121 }
122
123 void
124 nv10_emit_fog(struct gl_context *ctx, int emit)
125 {
126         struct nouveau_context *nctx = to_nouveau_context(ctx);
127         struct nouveau_channel *chan = context_chan(ctx);
128         struct nouveau_grobj *celsius = context_eng3d(ctx);
129         struct gl_fog_attrib *f = &ctx->Fog;
130         unsigned source = nctx->fallback == HWTNL ?
131                 f->FogCoordinateSource : GL_FOG_COORDINATE_EXT;
132         float k[3];
133
134         nv10_get_fog_coeff(ctx, k);
135
136         BEGIN_RING(chan, celsius, NV10_3D_FOG_MODE, 4);
137         OUT_RING(chan, get_fog_mode(f->Mode));
138         OUT_RING(chan, get_fog_source(source));
139         OUT_RINGb(chan, f->Enabled);
140         OUT_RING(chan, pack_rgba_f(MESA_FORMAT_RGBA8888_REV, f->Color));
141
142         BEGIN_RING(chan, celsius, NV10_3D_FOG_COEFF(0), 3);
143         OUT_RINGp(chan, k, 3);
144
145         context_dirty(ctx, FRAG);
146 }
147
148 static inline unsigned
149 get_light_mode(struct gl_light *l)
150 {
151         if (l->Enabled) {
152                 if (l->_Flags & LIGHT_SPOT)
153                         return NV10_3D_ENABLED_LIGHTS_0_DIRECTIONAL;
154                 else if (l->_Flags & LIGHT_POSITIONAL)
155                         return NV10_3D_ENABLED_LIGHTS_0_POSITIONAL;
156                 else
157                         return NV10_3D_ENABLED_LIGHTS_0_NONPOSITIONAL;
158         } else {
159                 return NV10_3D_ENABLED_LIGHTS_0_DISABLED;
160         }
161 }
162
163 void
164 nv10_emit_light_enable(struct gl_context *ctx, int emit)
165 {
166         struct nouveau_context *nctx = to_nouveau_context(ctx);
167         struct nouveau_channel *chan = context_chan(ctx);
168         struct nouveau_grobj *celsius = context_eng3d(ctx);
169         uint32_t en_lights = 0;
170         int i;
171
172         if (nctx->fallback != HWTNL) {
173                 BEGIN_RING(chan, celsius, NV10_3D_LIGHTING_ENABLE, 1);
174                 OUT_RING(chan, 0);
175                 return;
176         }
177
178         for (i = 0; i < MAX_LIGHTS; i++)
179                 en_lights |= get_light_mode(&ctx->Light.Light[i]) << 2 * i;
180
181         BEGIN_RING(chan, celsius, NV10_3D_ENABLED_LIGHTS, 1);
182         OUT_RING(chan, en_lights);
183         BEGIN_RING(chan, celsius, NV10_3D_LIGHTING_ENABLE, 1);
184         OUT_RINGb(chan, ctx->Light.Enabled);
185         BEGIN_RING(chan, celsius, NV10_3D_NORMALIZE_ENABLE, 1);
186         OUT_RINGb(chan, ctx->Transform.Normalize);
187 }
188
189 void
190 nv10_emit_light_model(struct gl_context *ctx, int emit)
191 {
192         struct nouveau_channel *chan = context_chan(ctx);
193         struct nouveau_grobj *celsius = context_eng3d(ctx);
194         struct gl_lightmodel *m = &ctx->Light.Model;
195
196         BEGIN_RING(chan, celsius, NV10_3D_SEPARATE_SPECULAR_ENABLE, 1);
197         OUT_RINGb(chan, m->ColorControl == GL_SEPARATE_SPECULAR_COLOR);
198
199         BEGIN_RING(chan, celsius, NV10_3D_LIGHT_MODEL, 1);
200         OUT_RING(chan, ((m->LocalViewer ?
201                          NV10_3D_LIGHT_MODEL_LOCAL_VIEWER : 0) |
202                         (_mesa_need_secondary_color(ctx) ?
203                          NV10_3D_LIGHT_MODEL_SEPARATE_SPECULAR : 0) |
204                         (!ctx->Light.Enabled && ctx->Fog.ColorSumEnabled ?
205                          NV10_3D_LIGHT_MODEL_VERTEX_SPECULAR : 0)));
206 }
207
208 static float
209 get_shine(const float p[], float x)
210 {
211         const int n = 15;
212         const float *y = &p[1];
213         float f = (n - 1) * (1 - 1 / (1 + p[0] * x))
214                 / (1 - 1 / (1 + p[0] * 1024));
215         int i = f;
216
217         /* Linear interpolation in f-space (Faster and somewhat more
218          * accurate than x-space). */
219         if (x == 0)
220                 return y[0];
221         else if (i > n - 2)
222                 return y[n - 1];
223         else
224                 return y[i] + (y[i + 1] - y[i]) * (f - i);
225 }
226
227 static const float nv10_spot_params[2][16] = {
228         { 0.02, -3.80e-05, -1.77, -2.41, -2.71, -2.88, -2.98, -3.06,
229           -3.11, -3.17, -3.23, -3.28, -3.37, -3.47, -3.83, -5.11 },
230         { 0.02, -0.01, 1.77, 2.39, 2.70, 2.87, 2.98, 3.06,
231           3.10, 3.16, 3.23, 3.27, 3.37, 3.47, 3.83, 5.11 },
232 };
233
234 void
235 nv10_get_spot_coeff(struct gl_light *l, float k[7])
236 {
237         float e = l->SpotExponent;
238         float a0, b0, a1, a2, b2, a3;
239
240         if (e > 0)
241                 a0 = -1 - 5.36e-3 / sqrt(e);
242         else
243                 a0 = -1;
244         b0 = 1 / (1 + 0.273 * e);
245
246         a1 = get_shine(nv10_spot_params[0], e);
247
248         a2 = get_shine(nv10_spot_params[1], e);
249         b2 = 1 / (1 + 0.273 * e);
250
251         a3 = 0.9 + 0.278 * e;
252
253         if (l->SpotCutoff > 0) {
254                 float cutoff = MAX2(a3, 1 / (1 - l->_CosCutoff));
255
256                 k[0] = MAX2(0, a0 + b0 * cutoff);
257                 k[1] = a1;
258                 k[2] = a2 + b2 * cutoff;
259                 k[3] = - cutoff * l->_NormSpotDirection[0];
260                 k[4] = - cutoff * l->_NormSpotDirection[1];
261                 k[5] = - cutoff * l->_NormSpotDirection[2];
262                 k[6] = 1 - cutoff;
263
264         } else {
265                 k[0] = b0;
266                 k[1] = a1;
267                 k[2] = a2 + b2;
268                 k[3] = - l->_NormSpotDirection[0];
269                 k[4] = - l->_NormSpotDirection[1];
270                 k[5] = - l->_NormSpotDirection[2];
271                 k[6] = -1;
272         }
273 }
274
275 void
276 nv10_emit_light_source(struct gl_context *ctx, int emit)
277 {
278         const int i = emit - NOUVEAU_STATE_LIGHT_SOURCE0;
279         struct nouveau_channel *chan = context_chan(ctx);
280         struct nouveau_grobj *celsius = context_eng3d(ctx);
281         struct gl_light *l = &ctx->Light.Light[i];
282
283         if (l->_Flags & LIGHT_POSITIONAL) {
284                 BEGIN_RING(chan, celsius, NV10_3D_LIGHT_POSITION_X(i), 3);
285                 OUT_RINGp(chan, l->_Position, 3);
286
287                 BEGIN_RING(chan, celsius,
288                            NV10_3D_LIGHT_ATTENUATION_CONSTANT(i), 3);
289                 OUT_RINGf(chan, l->ConstantAttenuation);
290                 OUT_RINGf(chan, l->LinearAttenuation);
291                 OUT_RINGf(chan, l->QuadraticAttenuation);
292
293         } else {
294                 BEGIN_RING(chan, celsius, NV10_3D_LIGHT_DIRECTION_X(i), 3);
295                 OUT_RINGp(chan, l->_VP_inf_norm, 3);
296
297                 BEGIN_RING(chan, celsius, NV10_3D_LIGHT_HALF_VECTOR_X(i), 3);
298                 OUT_RINGp(chan, l->_h_inf_norm, 3);
299         }
300
301         if (l->_Flags & LIGHT_SPOT) {
302                 float k[7];
303
304                 nv10_get_spot_coeff(l, k);
305
306                 BEGIN_RING(chan, celsius, NV10_3D_LIGHT_SPOT_CUTOFF(i, 0), 7);
307                 OUT_RINGp(chan, k, 7);
308         }
309 }
310
311 #define USE_COLOR_MATERIAL(attr)                                        \
312         (ctx->Light.ColorMaterialEnabled &&                             \
313          ctx->Light.ColorMaterialBitmask & (1 << MAT_ATTRIB_FRONT_##attr))
314
315 void
316 nv10_emit_material_ambient(struct gl_context *ctx, int emit)
317 {
318         struct nouveau_channel *chan = context_chan(ctx);
319         struct nouveau_grobj *celsius = context_eng3d(ctx);
320         float (*mat)[4] = ctx->Light.Material.Attrib;
321         float c_scene[3], c_factor[3];
322         struct gl_light *l;
323
324         if (USE_COLOR_MATERIAL(AMBIENT)) {
325                 COPY_3V(c_scene, ctx->Light.Model.Ambient);
326                 COPY_3V(c_factor, mat[MAT_ATTRIB_FRONT_EMISSION]);
327
328         } else if (USE_COLOR_MATERIAL(EMISSION)) {
329                 SCALE_3V(c_scene, mat[MAT_ATTRIB_FRONT_AMBIENT],
330                          ctx->Light.Model.Ambient);
331                 ZERO_3V(c_factor);
332
333         } else {
334                 COPY_3V(c_scene, ctx->Light._BaseColor[0]);
335                 ZERO_3V(c_factor);
336         }
337
338         BEGIN_RING(chan, celsius, NV10_3D_LIGHT_MODEL_AMBIENT_R, 3);
339         OUT_RINGp(chan, c_scene, 3);
340
341         if (ctx->Light.ColorMaterialEnabled) {
342                 BEGIN_RING(chan, celsius, NV10_3D_MATERIAL_FACTOR_R, 3);
343                 OUT_RINGp(chan, c_factor, 3);
344         }
345
346         foreach(l, &ctx->Light.EnabledList) {
347                 const int i = l - ctx->Light.Light;
348                 float *c_light = (USE_COLOR_MATERIAL(AMBIENT) ?
349                                   l->Ambient :
350                                   l->_MatAmbient[0]);
351
352                 BEGIN_RING(chan, celsius, NV10_3D_LIGHT_AMBIENT_R(i), 3);
353                 OUT_RINGp(chan, c_light, 3);
354         }
355 }
356
357 void
358 nv10_emit_material_diffuse(struct gl_context *ctx, int emit)
359 {
360         struct nouveau_channel *chan = context_chan(ctx);
361         struct nouveau_grobj *celsius = context_eng3d(ctx);
362         GLfloat (*mat)[4] = ctx->Light.Material.Attrib;
363         struct gl_light *l;
364
365         BEGIN_RING(chan, celsius, NV10_3D_MATERIAL_FACTOR_A, 1);
366         OUT_RINGf(chan, mat[MAT_ATTRIB_FRONT_DIFFUSE][3]);
367
368         foreach(l, &ctx->Light.EnabledList) {
369                 const int i = l - ctx->Light.Light;
370                 float *c_light = (USE_COLOR_MATERIAL(DIFFUSE) ?
371                                   l->Diffuse :
372                                   l->_MatDiffuse[0]);
373
374                 BEGIN_RING(chan, celsius, NV10_3D_LIGHT_DIFFUSE_R(i), 3);
375                 OUT_RINGp(chan, c_light, 3);
376         }
377 }
378
379 void
380 nv10_emit_material_specular(struct gl_context *ctx, int emit)
381 {
382         struct nouveau_channel *chan = context_chan(ctx);
383         struct nouveau_grobj *celsius = context_eng3d(ctx);
384         struct gl_light *l;
385
386         foreach(l, &ctx->Light.EnabledList) {
387                 const int i = l - ctx->Light.Light;
388                 float *c_light = (USE_COLOR_MATERIAL(SPECULAR) ?
389                                   l->Specular :
390                                   l->_MatSpecular[0]);
391
392                 BEGIN_RING(chan, celsius, NV10_3D_LIGHT_SPECULAR_R(i), 3);
393                 OUT_RINGp(chan, c_light, 3);
394         }
395 }
396
397 static const float nv10_shininess_param[6][16] = {
398         { 0.70, 0.00, 0.06, 0.06, 0.05, 0.04, 0.02, 0.00,
399           -0.06, -0.13, -0.24, -0.36, -0.51, -0.66, -0.82, -1.00 },
400         { 0.01, 1.00, -2.29, -2.77, -2.96, -3.06, -3.12, -3.18,
401           -3.24, -3.29, -3.36, -3.43, -3.51, -3.75, -4.33, -5.11 },
402         { 0.02, 0.00, 2.28, 2.75, 2.94, 3.04, 3.1, 3.15,
403           3.18, 3.22, 3.27, 3.32, 3.39, 3.48, 3.84, 5.11 },
404         { 0.70, 0.00, 0.05, 0.06, 0.06, 0.06, 0.05, 0.04,
405           0.02, 0.01, -0.03, -0.12, -0.25, -0.43, -0.68, -0.99 },
406         { 0.01, 1.00, -1.61, -2.35, -2.67, -2.84, -2.96, -3.05,
407           -3.08, -3.14, -3.2, -3.26, -3.32, -3.42, -3.54, -4.21 },
408         { 0.01, 0.00, 2.25, 2.73, 2.92, 3.03, 3.09, 3.15,
409           3.16, 3.21, 3.25, 3.29, 3.35, 3.43, 3.56, 4.22 },
410 };
411
412 void
413 nv10_get_shininess_coeff(float s, float k[6])
414 {
415         int i;
416
417         for (i = 0; i < 6; i++)
418                 k[i] = get_shine(nv10_shininess_param[i], s);
419 }
420
421 void
422 nv10_emit_material_shininess(struct gl_context *ctx, int emit)
423 {
424         struct nouveau_channel *chan = context_chan(ctx);
425         struct nouveau_grobj *celsius = context_eng3d(ctx);
426         float (*mat)[4] = ctx->Light.Material.Attrib;
427         float k[6];
428
429         nv10_get_shininess_coeff(
430                 CLAMP(mat[MAT_ATTRIB_FRONT_SHININESS][0], 0, 1024),
431                 k);
432
433         BEGIN_RING(chan, celsius, NV10_3D_MATERIAL_SHININESS(0), 6);
434         OUT_RINGp(chan, k, 6);
435 }
436
437 void
438 nv10_emit_modelview(struct gl_context *ctx, int emit)
439 {
440         struct nouveau_context *nctx = to_nouveau_context(ctx);
441         struct nouveau_channel *chan = context_chan(ctx);
442         struct nouveau_grobj *celsius = context_eng3d(ctx);
443         GLmatrix *m = ctx->ModelviewMatrixStack.Top;
444
445         if (nctx->fallback != HWTNL)
446                 return;
447
448         if (ctx->Light._NeedEyeCoords || ctx->Fog.Enabled ||
449             (ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD)) {
450                 BEGIN_RING(chan, celsius, NV10_3D_MODELVIEW_MATRIX(0, 0), 16);
451                 OUT_RINGm(chan, m->m);
452         }
453
454         if (ctx->Light.Enabled ||
455             (ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD)) {
456                 int i, j;
457
458                 BEGIN_RING(chan, celsius,
459                            NV10_3D_INVERSE_MODELVIEW_MATRIX(0, 0), 12);
460                 for (i = 0; i < 3; i++)
461                         for (j = 0; j < 4; j++)
462                                 OUT_RINGf(chan, m->inv[4*i + j]);
463         }
464 }
465
466 void
467 nv10_emit_point_parameter(struct gl_context *ctx, int emit)
468 {
469 }
470
471 void
472 nv10_emit_projection(struct gl_context *ctx, int emit)
473 {
474         struct nouveau_context *nctx = to_nouveau_context(ctx);
475         struct nouveau_channel *chan = context_chan(ctx);
476         struct nouveau_grobj *celsius = context_eng3d(ctx);
477         GLmatrix m;
478
479         _math_matrix_ctr(&m);
480         get_viewport_scale(ctx, m.m);
481
482         if (nv10_use_viewport_zclear(ctx))
483                 m.m[MAT_SZ] /= 8;
484
485         if (nctx->fallback == HWTNL)
486                 _math_matrix_mul_matrix(&m, &m, &ctx->_ModelProjectMatrix);
487
488         BEGIN_RING(chan, celsius, NV10_3D_PROJECTION_MATRIX(0), 16);
489         OUT_RINGm(chan, m.m);
490
491         _math_matrix_dtr(&m);
492 }