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 "nv20_3d.xml.h"
32#include "nv10_driver.h"
33#include "nv20_driver.h"
34#include "util/bitscan.h"
35
36#define LIGHT_MODEL_AMBIENT_R(side)			\
37	((side) ? NV20_3D_LIGHT_MODEL_BACK_AMBIENT_R :	\
38	 NV20_3D_LIGHT_MODEL_FRONT_AMBIENT_R)
39#define LIGHT_AMBIENT_R(side, i)			\
40	((side) ? NV20_3D_LIGHT_BACK_AMBIENT_R(i) :	\
41	 NV20_3D_LIGHT_FRONT_AMBIENT_R(i))
42#define LIGHT_DIFFUSE_R(side, i)			\
43	((side) ? NV20_3D_LIGHT_BACK_DIFFUSE_R(i) :	\
44	 NV20_3D_LIGHT_FRONT_DIFFUSE_R(i))
45#define LIGHT_SPECULAR_R(side, i)			\
46	((side) ? NV20_3D_LIGHT_BACK_SPECULAR_R(i) :	\
47	 NV20_3D_LIGHT_FRONT_SPECULAR_R(i))
48#define MATERIAL_FACTOR_R(side)				\
49	((side) ? NV20_3D_MATERIAL_FACTOR_BACK_R :	\
50	 NV20_3D_MATERIAL_FACTOR_FRONT_R)
51#define MATERIAL_FACTOR_A(side)				\
52	((side) ? NV20_3D_MATERIAL_FACTOR_BACK_A :	\
53	 NV20_3D_MATERIAL_FACTOR_FRONT_A)
54#define MATERIAL_SHININESS(side)			\
55	((side) ? NV20_3D_BACK_MATERIAL_SHININESS(0) :	\
56	 NV20_3D_FRONT_MATERIAL_SHININESS(0))
57
58void
59nv20_emit_clip_plane(struct gl_context *ctx, int emit)
60{
61}
62
63static inline unsigned
64get_material_bitmask(unsigned m)
65{
66	unsigned ret = 0;
67
68	if (m & MAT_BIT_FRONT_EMISSION)
69		ret |= NV20_3D_COLOR_MATERIAL_FRONT_EMISSION_COL1;
70	if (m & MAT_BIT_FRONT_AMBIENT)
71		ret |= NV20_3D_COLOR_MATERIAL_FRONT_AMBIENT_COL1;
72	if (m & MAT_BIT_FRONT_DIFFUSE)
73		ret |= NV20_3D_COLOR_MATERIAL_FRONT_DIFFUSE_COL1;
74	if (m & MAT_BIT_FRONT_SPECULAR)
75		ret |= NV20_3D_COLOR_MATERIAL_FRONT_SPECULAR_COL1;
76
77	if (m & MAT_BIT_BACK_EMISSION)
78		ret |= NV20_3D_COLOR_MATERIAL_BACK_EMISSION_COL1;
79	if (m & MAT_BIT_BACK_AMBIENT)
80		ret |= NV20_3D_COLOR_MATERIAL_BACK_AMBIENT_COL1;
81	if (m & MAT_BIT_BACK_DIFFUSE)
82		ret |= NV20_3D_COLOR_MATERIAL_BACK_DIFFUSE_COL1;
83	if (m & MAT_BIT_BACK_SPECULAR)
84		ret |= NV20_3D_COLOR_MATERIAL_BACK_SPECULAR_COL1;
85
86	return ret;
87}
88
89void
90nv20_emit_color_material(struct gl_context *ctx, int emit)
91{
92	struct nouveau_pushbuf *push = context_push(ctx);
93	unsigned mask = get_material_bitmask(ctx->Light._ColorMaterialBitmask);
94
95	BEGIN_NV04(push, NV20_3D(COLOR_MATERIAL), 1);
96	PUSH_DATA (push, ctx->Light.ColorMaterialEnabled ? mask : 0);
97}
98
99static unsigned
100get_fog_mode_signed(unsigned mode)
101{
102	switch (mode) {
103	case GL_LINEAR:
104		return NV20_3D_FOG_MODE_LINEAR_SIGNED;
105	case GL_EXP:
106		return NV20_3D_FOG_MODE_EXP_SIGNED;
107	case GL_EXP2:
108		return NV20_3D_FOG_MODE_EXP2_SIGNED;
109	default:
110		assert(0);
111	}
112}
113
114static unsigned
115get_fog_mode_unsigned(unsigned mode)
116{
117	switch (mode) {
118	case GL_LINEAR:
119		return NV20_3D_FOG_MODE_LINEAR_UNSIGNED;
120	case GL_EXP:
121		return NV20_3D_FOG_MODE_EXP_UNSIGNED;
122	case GL_EXP2:
123		return NV20_3D_FOG_MODE_EXP2_UNSIGNED;
124	default:
125		assert(0);
126	}
127}
128
129static unsigned
130get_fog_source(unsigned source, unsigned distance_mode)
131{
132	switch (source) {
133	case GL_FOG_COORDINATE_EXT:
134		return NV20_3D_FOG_COORD_FOG;
135	case GL_FRAGMENT_DEPTH_EXT:
136		switch (distance_mode) {
137		case GL_EYE_PLANE_ABSOLUTE_NV:
138			return NV20_3D_FOG_COORD_DIST_ORTHOGONAL_ABS;
139		case GL_EYE_PLANE:
140			return NV20_3D_FOG_COORD_DIST_ORTHOGONAL;
141		case GL_EYE_RADIAL_NV:
142			return NV20_3D_FOG_COORD_DIST_RADIAL;
143		default:
144			assert(0);
145		}
146	default:
147		assert(0);
148	}
149}
150
151void
152nv20_emit_fog(struct gl_context *ctx, int emit)
153{
154	struct nouveau_context *nctx = to_nouveau_context(ctx);
155	struct nouveau_pushbuf *push = context_push(ctx);
156	struct gl_fog_attrib *f = &ctx->Fog;
157	unsigned source = nctx->fallback == HWTNL ?
158		f->FogCoordinateSource : GL_FOG_COORDINATE_EXT;
159	float k[3];
160
161	nv10_get_fog_coeff(ctx, k);
162
163	BEGIN_NV04(push, NV20_3D(FOG_MODE), 4);
164	PUSH_DATA (push, ((source == GL_FRAGMENT_DEPTH_EXT &&
165			 f->FogDistanceMode == GL_EYE_PLANE_ABSOLUTE_NV) ?
166			get_fog_mode_unsigned(f->Mode) :
167			get_fog_mode_signed(f->Mode)));
168	PUSH_DATA (push, get_fog_source(source, f->FogDistanceMode));
169	PUSH_DATAb(push, f->Enabled);
170	PUSH_DATA (push, pack_rgba_f(MESA_FORMAT_R8G8B8A8_UNORM, f->Color));
171
172	BEGIN_NV04(push, NV20_3D(FOG_COEFF(0)), 3);
173	PUSH_DATAp(push, k, 3);
174}
175
176void
177nv20_emit_light_model(struct gl_context *ctx, int emit)
178{
179	struct nouveau_pushbuf *push = context_push(ctx);
180	struct gl_lightmodel *m = &ctx->Light.Model;
181
182	BEGIN_NV04(push, NV20_3D(SEPARATE_SPECULAR_ENABLE), 1);
183	PUSH_DATAb(push, m->ColorControl == GL_SEPARATE_SPECULAR_COLOR);
184
185	BEGIN_NV04(push, NV20_3D(LIGHT_MODEL), 1);
186	PUSH_DATA (push, ((m->LocalViewer ?
187			 NV20_3D_LIGHT_MODEL_VIEWER_LOCAL :
188			 NV20_3D_LIGHT_MODEL_VIEWER_NONLOCAL) |
189			(_mesa_need_secondary_color(ctx) ?
190			 NV20_3D_LIGHT_MODEL_SEPARATE_SPECULAR :
191			 0)));
192
193	BEGIN_NV04(push, NV20_3D(LIGHT_MODEL_TWO_SIDE_ENABLE), 1);
194	PUSH_DATAb(push, ctx->Light.Model.TwoSide);
195}
196
197void
198nv20_emit_light_source(struct gl_context *ctx, int emit)
199{
200	const int i = emit - NOUVEAU_STATE_LIGHT_SOURCE0;
201	struct nouveau_pushbuf *push = context_push(ctx);
202	struct gl_light *l = &ctx->Light.Light[i];
203        struct gl_light_uniforms *lu = &ctx->Light.LightSource[i];
204
205	if (l->_Flags & LIGHT_POSITIONAL) {
206		BEGIN_NV04(push, NV20_3D(LIGHT_POSITION_X(i)), 3);
207		PUSH_DATAp(push, l->_Position, 3);
208
209		BEGIN_NV04(push, NV20_3D(LIGHT_ATTENUATION_CONSTANT(i)), 3);
210		PUSH_DATAf(push, lu->ConstantAttenuation);
211		PUSH_DATAf(push, lu->LinearAttenuation);
212		PUSH_DATAf(push, lu->QuadraticAttenuation);
213
214	} else {
215		BEGIN_NV04(push, NV20_3D(LIGHT_DIRECTION_X(i)), 3);
216		PUSH_DATAp(push, l->_VP_inf_norm, 3);
217
218		BEGIN_NV04(push, NV20_3D(LIGHT_HALF_VECTOR_X(i)), 3);
219		PUSH_DATAp(push, l->_h_inf_norm, 3);
220	}
221
222	if (l->_Flags & LIGHT_SPOT) {
223		float k[7];
224
225		nv10_get_spot_coeff(l, lu, k);
226
227		BEGIN_NV04(push, NV20_3D(LIGHT_SPOT_CUTOFF(i, 0)), 7);
228		PUSH_DATAp(push, k, 7);
229	}
230}
231
232#define USE_COLOR_MATERIAL(attr, side)					\
233	(ctx->Light.ColorMaterialEnabled &&				\
234	 ctx->Light._ColorMaterialBitmask & (1 << MAT_ATTRIB_##attr(side)))
235
236void
237nv20_emit_material_ambient(struct gl_context *ctx, int emit)
238{
239	const int side = emit - NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT;
240	struct nouveau_pushbuf *push = context_push(ctx);
241	float (*mat)[4] = ctx->Light.Material.Attrib;
242	float c_scene[3], c_factor[3];
243	GLbitfield mask;
244
245	if (USE_COLOR_MATERIAL(AMBIENT, side)) {
246		COPY_3V(c_scene, mat[MAT_ATTRIB_EMISSION(side)]);
247		COPY_3V(c_factor, ctx->Light.Model.Ambient);
248
249	} else if (USE_COLOR_MATERIAL(EMISSION, side)) {
250		SCALE_3V(c_scene, mat[MAT_ATTRIB_AMBIENT(side)],
251			 ctx->Light.Model.Ambient);
252		ASSIGN_3V(c_factor, 1, 1, 1);
253
254	} else {
255		COPY_3V(c_scene, ctx->Light._BaseColor[side]);
256		ZERO_3V(c_factor);
257	}
258
259	BEGIN_NV04(push, SUBC_3D(LIGHT_MODEL_AMBIENT_R(side)), 3);
260	PUSH_DATAp(push, c_scene, 3);
261
262	if (ctx->Light.ColorMaterialEnabled) {
263		BEGIN_NV04(push, SUBC_3D(MATERIAL_FACTOR_R(side)), 3);
264		PUSH_DATAp(push, c_factor, 3);
265	}
266
267	mask = ctx->Light._EnabledLights;
268	while (mask) {
269		const int i = u_bit_scan(&mask);
270		struct gl_light *l = &ctx->Light.Light[i];
271                struct gl_light_uniforms *lu = &ctx->Light.LightSource[i];
272		float *c_light = (USE_COLOR_MATERIAL(AMBIENT, side) ?
273				  lu->Ambient :
274				  l->_MatAmbient[side]);
275
276		BEGIN_NV04(push, SUBC_3D(LIGHT_AMBIENT_R(side, i)), 3);
277		PUSH_DATAp(push, c_light, 3);
278	}
279}
280
281void
282nv20_emit_material_diffuse(struct gl_context *ctx, int emit)
283{
284	const int side = emit - NOUVEAU_STATE_MATERIAL_FRONT_DIFFUSE;
285	struct nouveau_pushbuf *push = context_push(ctx);
286	GLfloat (*mat)[4] = ctx->Light.Material.Attrib;
287	GLbitfield mask;
288
289	BEGIN_NV04(push, SUBC_3D(MATERIAL_FACTOR_A(side)), 1);
290	PUSH_DATAf(push, mat[MAT_ATTRIB_DIFFUSE(side)][3]);
291
292	mask = ctx->Light._EnabledLights;
293	while (mask) {
294		const int i = u_bit_scan(&mask);
295		struct gl_light *l = &ctx->Light.Light[i];
296                struct gl_light_uniforms *lu = &ctx->Light.LightSource[i];
297		float *c_light = (USE_COLOR_MATERIAL(DIFFUSE, side) ?
298				  lu->Diffuse :
299				  l->_MatDiffuse[side]);
300
301		BEGIN_NV04(push, SUBC_3D(LIGHT_DIFFUSE_R(side, i)), 3);
302		PUSH_DATAp(push, c_light, 3);
303	}
304}
305
306void
307nv20_emit_material_specular(struct gl_context *ctx, int emit)
308{
309	const int side = emit - NOUVEAU_STATE_MATERIAL_FRONT_SPECULAR;
310	struct nouveau_pushbuf *push = context_push(ctx);
311	GLbitfield mask;
312
313	mask = ctx->Light._EnabledLights;
314	while (mask) {
315		const int i = u_bit_scan(&mask);
316		struct gl_light *l = &ctx->Light.Light[i];
317                struct gl_light_uniforms *lu = &ctx->Light.LightSource[i];
318		float *c_light = (USE_COLOR_MATERIAL(SPECULAR, side) ?
319				  lu->Specular :
320				  l->_MatSpecular[side]);
321
322		BEGIN_NV04(push, SUBC_3D(LIGHT_SPECULAR_R(side, i)), 3);
323		PUSH_DATAp(push, c_light, 3);
324	}
325}
326
327void
328nv20_emit_material_shininess(struct gl_context *ctx, int emit)
329{
330	const int side = emit - NOUVEAU_STATE_MATERIAL_FRONT_SHININESS;
331	struct nouveau_pushbuf *push = context_push(ctx);
332	float (*mat)[4] = ctx->Light.Material.Attrib;
333	float k[6];
334
335	nv10_get_shininess_coeff(
336		CLAMP(mat[MAT_ATTRIB_SHININESS(side)][0], 0, 1024),
337		k);
338
339	BEGIN_NV04(push, SUBC_3D(MATERIAL_SHININESS(side)), 6);
340	PUSH_DATAp(push, k, 6);
341}
342
343void
344nv20_emit_modelview(struct gl_context *ctx, int emit)
345{
346	struct nouveau_context *nctx = to_nouveau_context(ctx);
347	struct nouveau_pushbuf *push = context_push(ctx);
348	GLmatrix *m = ctx->ModelviewMatrixStack.Top;
349
350	if (nctx->fallback != HWTNL)
351		return;
352
353	if (ctx->Light._NeedEyeCoords || ctx->Fog.Enabled ||
354	    (ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD)) {
355		BEGIN_NV04(push, NV20_3D(MODELVIEW_MATRIX(0, 0)), 16);
356		PUSH_DATAm(push, m->m);
357	}
358
359	if (ctx->Light.Enabled ||
360	    (ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD)) {
361		int i, j;
362
363		BEGIN_NV04(push, NV20_3D(INVERSE_MODELVIEW_MATRIX(0, 0)), 12);
364		for (i = 0; i < 3; i++)
365			for (j = 0; j < 4; j++)
366				PUSH_DATAf(push, m->inv[4*i + j]);
367	}
368}
369
370void
371nv20_emit_projection(struct gl_context *ctx, int emit)
372{
373	struct nouveau_context *nctx = to_nouveau_context(ctx);
374	struct nouveau_pushbuf *push = context_push(ctx);
375	GLmatrix m;
376
377	_math_matrix_ctr(&m);
378	get_viewport_scale(ctx, m.m);
379
380	if (nctx->fallback == HWTNL)
381		_math_matrix_mul_matrix(&m, &m, &ctx->_ModelProjectMatrix);
382
383	BEGIN_NV04(push, NV20_3D(PROJECTION_MATRIX(0)), 16);
384	PUSH_DATAm(push, m.m);
385}
386