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
204	if (l->_Flags & LIGHT_POSITIONAL) {
205		BEGIN_NV04(push, NV20_3D(LIGHT_POSITION_X(i)), 3);
206		PUSH_DATAp(push, l->_Position, 3);
207
208		BEGIN_NV04(push, NV20_3D(LIGHT_ATTENUATION_CONSTANT(i)), 3);
209		PUSH_DATAf(push, l->ConstantAttenuation);
210		PUSH_DATAf(push, l->LinearAttenuation);
211		PUSH_DATAf(push, l->QuadraticAttenuation);
212
213	} else {
214		BEGIN_NV04(push, NV20_3D(LIGHT_DIRECTION_X(i)), 3);
215		PUSH_DATAp(push, l->_VP_inf_norm, 3);
216
217		BEGIN_NV04(push, NV20_3D(LIGHT_HALF_VECTOR_X(i)), 3);
218		PUSH_DATAp(push, l->_h_inf_norm, 3);
219	}
220
221	if (l->_Flags & LIGHT_SPOT) {
222		float k[7];
223
224		nv10_get_spot_coeff(l, k);
225
226		BEGIN_NV04(push, NV20_3D(LIGHT_SPOT_CUTOFF(i, 0)), 7);
227		PUSH_DATAp(push, k, 7);
228	}
229}
230
231#define USE_COLOR_MATERIAL(attr, side)					\
232	(ctx->Light.ColorMaterialEnabled &&				\
233	 ctx->Light._ColorMaterialBitmask & (1 << MAT_ATTRIB_##attr(side)))
234
235void
236nv20_emit_material_ambient(struct gl_context *ctx, int emit)
237{
238	const int side = emit - NOUVEAU_STATE_MATERIAL_FRONT_AMBIENT;
239	struct nouveau_pushbuf *push = context_push(ctx);
240	float (*mat)[4] = ctx->Light.Material.Attrib;
241	float c_scene[3], c_factor[3];
242	GLbitfield mask;
243
244	if (USE_COLOR_MATERIAL(AMBIENT, side)) {
245		COPY_3V(c_scene, mat[MAT_ATTRIB_EMISSION(side)]);
246		COPY_3V(c_factor, ctx->Light.Model.Ambient);
247
248	} else if (USE_COLOR_MATERIAL(EMISSION, side)) {
249		SCALE_3V(c_scene, mat[MAT_ATTRIB_AMBIENT(side)],
250			 ctx->Light.Model.Ambient);
251		ASSIGN_3V(c_factor, 1, 1, 1);
252
253	} else {
254		COPY_3V(c_scene, ctx->Light._BaseColor[side]);
255		ZERO_3V(c_factor);
256	}
257
258	BEGIN_NV04(push, SUBC_3D(LIGHT_MODEL_AMBIENT_R(side)), 3);
259	PUSH_DATAp(push, c_scene, 3);
260
261	if (ctx->Light.ColorMaterialEnabled) {
262		BEGIN_NV04(push, SUBC_3D(MATERIAL_FACTOR_R(side)), 3);
263		PUSH_DATAp(push, c_factor, 3);
264	}
265
266	mask = ctx->Light._EnabledLights;
267	while (mask) {
268		const int i = u_bit_scan(&mask);
269		struct gl_light *l = &ctx->Light.Light[i];
270		float *c_light = (USE_COLOR_MATERIAL(AMBIENT, side) ?
271				  l->Ambient :
272				  l->_MatAmbient[side]);
273
274		BEGIN_NV04(push, SUBC_3D(LIGHT_AMBIENT_R(side, i)), 3);
275		PUSH_DATAp(push, c_light, 3);
276	}
277}
278
279void
280nv20_emit_material_diffuse(struct gl_context *ctx, int emit)
281{
282	const int side = emit - NOUVEAU_STATE_MATERIAL_FRONT_DIFFUSE;
283	struct nouveau_pushbuf *push = context_push(ctx);
284	GLfloat (*mat)[4] = ctx->Light.Material.Attrib;
285	GLbitfield mask;
286
287	BEGIN_NV04(push, SUBC_3D(MATERIAL_FACTOR_A(side)), 1);
288	PUSH_DATAf(push, mat[MAT_ATTRIB_DIFFUSE(side)][3]);
289
290	mask = ctx->Light._EnabledLights;
291	while (mask) {
292		const int i = u_bit_scan(&mask);
293		struct gl_light *l = &ctx->Light.Light[i];
294		float *c_light = (USE_COLOR_MATERIAL(DIFFUSE, side) ?
295				  l->Diffuse :
296				  l->_MatDiffuse[side]);
297
298		BEGIN_NV04(push, SUBC_3D(LIGHT_DIFFUSE_R(side, i)), 3);
299		PUSH_DATAp(push, c_light, 3);
300	}
301}
302
303void
304nv20_emit_material_specular(struct gl_context *ctx, int emit)
305{
306	const int side = emit - NOUVEAU_STATE_MATERIAL_FRONT_SPECULAR;
307	struct nouveau_pushbuf *push = context_push(ctx);
308	GLbitfield mask;
309
310	mask = ctx->Light._EnabledLights;
311	while (mask) {
312		const int i = u_bit_scan(&mask);
313		struct gl_light *l = &ctx->Light.Light[i];
314		float *c_light = (USE_COLOR_MATERIAL(SPECULAR, side) ?
315				  l->Specular :
316				  l->_MatSpecular[side]);
317
318		BEGIN_NV04(push, SUBC_3D(LIGHT_SPECULAR_R(side, i)), 3);
319		PUSH_DATAp(push, c_light, 3);
320	}
321}
322
323void
324nv20_emit_material_shininess(struct gl_context *ctx, int emit)
325{
326	const int side = emit - NOUVEAU_STATE_MATERIAL_FRONT_SHININESS;
327	struct nouveau_pushbuf *push = context_push(ctx);
328	float (*mat)[4] = ctx->Light.Material.Attrib;
329	float k[6];
330
331	nv10_get_shininess_coeff(
332		CLAMP(mat[MAT_ATTRIB_SHININESS(side)][0], 0, 1024),
333		k);
334
335	BEGIN_NV04(push, SUBC_3D(MATERIAL_SHININESS(side)), 6);
336	PUSH_DATAp(push, k, 6);
337}
338
339void
340nv20_emit_modelview(struct gl_context *ctx, int emit)
341{
342	struct nouveau_context *nctx = to_nouveau_context(ctx);
343	struct nouveau_pushbuf *push = context_push(ctx);
344	GLmatrix *m = ctx->ModelviewMatrixStack.Top;
345
346	if (nctx->fallback != HWTNL)
347		return;
348
349	if (ctx->Light._NeedEyeCoords || ctx->Fog.Enabled ||
350	    (ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD)) {
351		BEGIN_NV04(push, NV20_3D(MODELVIEW_MATRIX(0, 0)), 16);
352		PUSH_DATAm(push, m->m);
353	}
354
355	if (ctx->Light.Enabled ||
356	    (ctx->Texture._GenFlags & TEXGEN_NEED_EYE_COORD)) {
357		int i, j;
358
359		BEGIN_NV04(push, NV20_3D(INVERSE_MODELVIEW_MATRIX(0, 0)), 12);
360		for (i = 0; i < 3; i++)
361			for (j = 0; j < 4; j++)
362				PUSH_DATAf(push, m->inv[4*i + j]);
363	}
364}
365
366void
367nv20_emit_projection(struct gl_context *ctx, int emit)
368{
369	struct nouveau_context *nctx = to_nouveau_context(ctx);
370	struct nouveau_pushbuf *push = context_push(ctx);
371	GLmatrix m;
372
373	_math_matrix_ctr(&m);
374	get_viewport_scale(ctx, m.m);
375
376	if (nctx->fallback == HWTNL)
377		_math_matrix_mul_matrix(&m, &m, &ctx->_ModelProjectMatrix);
378
379	BEGIN_NV04(push, NV20_3D(PROJECTION_MATRIX(0)), 16);
380	PUSH_DATAm(push, m.m);
381
382	_math_matrix_dtr(&m);
383}
384