1 /*
2  * Copyright (C) 2009 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_texture.h"
31 #include "nv20_3d.xml.h"
32 #include "nouveau_util.h"
33 #include "nv20_driver.h"
34 #include "main/samplerobj.h"
35 
36 void
nv20_emit_tex_gen(struct gl_context * ctx,int emit)37 nv20_emit_tex_gen(struct gl_context *ctx, int emit)
38 {
39 	const int i = emit - NOUVEAU_STATE_TEX_GEN0;
40 	struct nouveau_context *nctx = to_nouveau_context(ctx);
41 	struct nouveau_pushbuf *push = context_push(ctx);
42 	struct gl_fixedfunc_texture_unit *unit =
43            &ctx->Texture.FixedFuncUnit[i];
44 	int j;
45 
46 	for (j = 0; j < 4; j++) {
47 		if (nctx->fallback == HWTNL && (unit->TexGenEnabled & 1 << j)) {
48 			struct gl_texgen *coord = get_texgen_coord(unit, j);
49 			float *k = get_texgen_coeff(unit, coord->Mode, j);
50 
51 			if (k) {
52 				BEGIN_NV04(push, NV20_3D(TEX_GEN_COEFF(i, j)), 4);
53 				PUSH_DATAp(push, k, 4);
54 			}
55 
56 			BEGIN_NV04(push, NV20_3D(TEX_GEN_MODE(i, j)), 1);
57 			PUSH_DATA (push, nvgl_texgen_mode(coord->Mode));
58 
59 		} else {
60 			BEGIN_NV04(push, NV20_3D(TEX_GEN_MODE(i, j)), 1);
61 			PUSH_DATA (push, 0);
62 		}
63 	}
64 }
65 
66 void
nv20_emit_tex_mat(struct gl_context * ctx,int emit)67 nv20_emit_tex_mat(struct gl_context *ctx, int emit)
68 {
69 	const int i = emit - NOUVEAU_STATE_TEX_MAT0;
70 	struct nouveau_context *nctx = to_nouveau_context(ctx);
71 	struct nouveau_pushbuf *push = context_push(ctx);
72 
73 	if (nctx->fallback == HWTNL &&
74 	    (ctx->Texture._TexMatEnabled & 1 << i)) {
75 		BEGIN_NV04(push, NV20_3D(TEX_MATRIX_ENABLE(i)), 1);
76 		PUSH_DATA (push, 1);
77 
78 		BEGIN_NV04(push, NV20_3D(TEX_MATRIX(i,0)), 16);
79 		PUSH_DATAm(push, ctx->TextureMatrixStack[i].Top->m);
80 
81 	} else {
82 		BEGIN_NV04(push, NV20_3D(TEX_MATRIX_ENABLE(i)), 1);
83 		PUSH_DATA (push, 0);
84 	}
85 }
86 
87 static uint32_t
get_tex_format_pot(struct gl_texture_image * ti)88 get_tex_format_pot(struct gl_texture_image *ti)
89 {
90 	switch (ti->TexFormat) {
91 	case MESA_FORMAT_B8G8R8A8_UNORM:
92 		return NV20_3D_TEX_FORMAT_FORMAT_A8R8G8B8;
93 
94 	case MESA_FORMAT_B5G5R5A1_UNORM:
95 		return NV20_3D_TEX_FORMAT_FORMAT_A1R5G5B5;
96 
97 	case MESA_FORMAT_B4G4R4A4_UNORM:
98 		return NV20_3D_TEX_FORMAT_FORMAT_A4R4G4B4;
99 
100 	case MESA_FORMAT_B8G8R8X8_UNORM:
101 		return NV20_3D_TEX_FORMAT_FORMAT_X8R8G8B8;
102 
103 	case MESA_FORMAT_B5G6R5_UNORM:
104 		return NV20_3D_TEX_FORMAT_FORMAT_R5G6B5;
105 
106 	case MESA_FORMAT_A_UNORM8:
107 	case MESA_FORMAT_I_UNORM8:
108 		return NV20_3D_TEX_FORMAT_FORMAT_I8;
109 
110 	case MESA_FORMAT_L_UNORM8:
111 		return NV20_3D_TEX_FORMAT_FORMAT_L8;
112 
113 	case MESA_FORMAT_RGB_DXT1:
114 	case MESA_FORMAT_RGBA_DXT1:
115 		return NV20_3D_TEX_FORMAT_FORMAT_DXT1;
116 
117 	case MESA_FORMAT_RGBA_DXT3:
118 		return NV20_3D_TEX_FORMAT_FORMAT_DXT3;
119 
120 	case MESA_FORMAT_RGBA_DXT5:
121 		return NV20_3D_TEX_FORMAT_FORMAT_DXT5;
122 
123 	default:
124 		assert(0);
125 	}
126 }
127 
128 static uint32_t
get_tex_format_rect(struct gl_texture_image * ti)129 get_tex_format_rect(struct gl_texture_image *ti)
130 {
131 	switch (ti->TexFormat) {
132 	case MESA_FORMAT_B8G8R8A8_UNORM:
133 		return NV20_3D_TEX_FORMAT_FORMAT_A8R8G8B8_RECT;
134 
135 	case MESA_FORMAT_B5G5R5A1_UNORM:
136 		return NV20_3D_TEX_FORMAT_FORMAT_A1R5G5B5_RECT;
137 
138 	case MESA_FORMAT_B4G4R4A4_UNORM:
139 		return NV20_3D_TEX_FORMAT_FORMAT_A4R4G4B4_RECT;
140 
141 	case MESA_FORMAT_B8G8R8X8_UNORM:
142 		return NV20_3D_TEX_FORMAT_FORMAT_R8G8B8_RECT;
143 
144 	case MESA_FORMAT_B5G6R5_UNORM:
145 		return NV20_3D_TEX_FORMAT_FORMAT_R5G6B5_RECT;
146 
147 	case MESA_FORMAT_L_UNORM8:
148 		return NV20_3D_TEX_FORMAT_FORMAT_L8_RECT;
149 
150 	case MESA_FORMAT_A_UNORM8:
151 	case MESA_FORMAT_I_UNORM8:
152 		return NV20_3D_TEX_FORMAT_FORMAT_I8_RECT;
153 
154 	default:
155 		assert(0);
156 	}
157 }
158 
159 void
nv20_emit_tex_obj(struct gl_context * ctx,int emit)160 nv20_emit_tex_obj(struct gl_context *ctx, int emit)
161 {
162 	const int i = emit - NOUVEAU_STATE_TEX_OBJ0;
163 	struct nouveau_pushbuf *push = context_push(ctx);
164 	const int bo_flags = NOUVEAU_BO_RD | NOUVEAU_BO_GART | NOUVEAU_BO_VRAM;
165 	struct gl_texture_object *t;
166 	struct nouveau_surface *s;
167 	struct gl_texture_image *ti;
168 	const struct gl_sampler_object *sa;
169 	uint8_t r, g, b, a;
170 	uint32_t tx_format, tx_filter, tx_wrap, tx_bcolor, tx_enable;
171 
172 	PUSH_RESET(push, BUFCTX_TEX(i));
173 
174 	if (!ctx->Texture.Unit[i]._Current) {
175 		BEGIN_NV04(push, NV20_3D(TEX_ENABLE(i)), 1);
176 		PUSH_DATA (push, 0);
177 
178 		context_dirty(ctx, TEX_SHADER);
179 		return;
180 	}
181 
182 	t = ctx->Texture.Unit[i]._Current;
183 	s = &to_nouveau_texture(t)->surfaces[t->Attrib.BaseLevel];
184 	ti = t->Image[0][t->Attrib.BaseLevel];
185 	sa = _mesa_get_samplerobj(ctx, i);
186 
187 	if (!nouveau_texture_validate(ctx, t))
188 		return;
189 
190 	/* Recompute the texturing registers. */
191 	tx_format = ti->DepthLog2 << 28
192 		| ti->HeightLog2 << 24
193 		| ti->WidthLog2 << 20
194 		| NV20_3D_TEX_FORMAT_DIMS_2D
195 		| NV20_3D_TEX_FORMAT_NO_BORDER
196 		| 1 << 16;
197 
198 	switch (t->Target) {
199 	case GL_TEXTURE_1D:
200 		tx_wrap = NV20_3D_TEX_WRAP_R_CLAMP_TO_EDGE
201 			| NV20_3D_TEX_WRAP_T_CLAMP_TO_EDGE
202 			| nvgl_wrap_mode_nv20(sa->Attrib.WrapS) << 0;
203 		break;
204 
205 	default:
206 		tx_wrap = nvgl_wrap_mode_nv20(sa->Attrib.WrapR) << 16
207 			| nvgl_wrap_mode_nv20(sa->Attrib.WrapT) << 8
208 			| nvgl_wrap_mode_nv20(sa->Attrib.WrapS) << 0;
209 		break;
210 	}
211 
212 	tx_filter = nvgl_filter_mode(sa->Attrib.MagFilter) << 24
213 		| nvgl_filter_mode(sa->Attrib.MinFilter) << 16
214 		| 2 << 12;
215 
216 	r = FLOAT_TO_UBYTE(sa->Attrib.state.border_color.f[0]);
217 	g = FLOAT_TO_UBYTE(sa->Attrib.state.border_color.f[1]);
218 	b = FLOAT_TO_UBYTE(sa->Attrib.state.border_color.f[2]);
219 	a = FLOAT_TO_UBYTE(sa->Attrib.state.border_color.f[3]);
220 	switch (ti->_BaseFormat) {
221 	case GL_LUMINANCE:
222 		a = 0xff;
223 		FALLTHROUGH;
224 	case GL_LUMINANCE_ALPHA:
225 		g = b = r;
226 		break;
227 	case GL_RGB:
228 		a = 0xff;
229 		break;
230 	case GL_INTENSITY:
231 		g = b = a = r;
232 		break;
233 	case GL_ALPHA:
234 		r = g = b = 0;
235 		break;
236 	}
237 	tx_bcolor = b << 0 | g << 8 | r << 16 | a << 24;
238 
239 	tx_enable = NV20_3D_TEX_ENABLE_ENABLE
240 		| log2i(sa->Attrib.MaxAnisotropy) << 4;
241 
242 	if (t->Target == GL_TEXTURE_RECTANGLE) {
243 		BEGIN_NV04(push, NV20_3D(TEX_NPOT_PITCH(i)), 1);
244 		PUSH_DATA (push, s->pitch << 16);
245 		BEGIN_NV04(push, NV20_3D(TEX_NPOT_SIZE(i)), 1);
246 		PUSH_DATA (push, s->width << 16 | s->height);
247 
248 		tx_format |= get_tex_format_rect(ti);
249 	} else {
250 		tx_format |= get_tex_format_pot(ti);
251 	}
252 
253 	if (sa->Attrib.MinFilter != GL_NEAREST &&
254 	    sa->Attrib.MinFilter != GL_LINEAR) {
255 		int lod_min = sa->Attrib.MinLod;
256 		int lod_max = MIN2(sa->Attrib.MaxLod, t->_MaxLambda);
257 		int lod_bias = sa->Attrib.LodBias
258 			+ ctx->Texture.Unit[i].LodBias;
259 
260 		lod_max = CLAMP(lod_max, 0, 15);
261 		lod_min = CLAMP(lod_min, 0, 15);
262 		lod_bias = CLAMP(lod_bias, 0, 15);
263 
264 		tx_format |= NV20_3D_TEX_FORMAT_MIPMAP;
265 		tx_filter |= lod_bias << 8;
266 		tx_enable |= lod_min << 26
267 			| lod_max << 14;
268 	}
269 
270 	/* Write it to the hardware. */
271 	BEGIN_NV04(push, NV20_3D(TEX_FORMAT(i)), 1);
272 	PUSH_MTHD (push, NV20_3D(TEX_FORMAT(i)), BUFCTX_TEX(i),
273 			 s->bo, tx_format, bo_flags | NOUVEAU_BO_OR,
274 			 NV20_3D_TEX_FORMAT_DMA0,
275 			 NV20_3D_TEX_FORMAT_DMA1);
276 
277 	BEGIN_NV04(push, NV20_3D(TEX_OFFSET(i)), 1);
278 	PUSH_MTHDl(push, NV20_3D(TEX_OFFSET(i)), BUFCTX_TEX(i),
279 			 s->bo, s->offset, bo_flags);
280 
281 	BEGIN_NV04(push, NV20_3D(TEX_WRAP(i)), 1);
282 	PUSH_DATA (push, tx_wrap);
283 
284 	BEGIN_NV04(push, NV20_3D(TEX_FILTER(i)), 1);
285 	PUSH_DATA (push, tx_filter);
286 
287 	BEGIN_NV04(push, NV20_3D(TEX_BORDER_COLOR(i)), 1);
288 	PUSH_DATA (push, tx_bcolor);
289 
290 	BEGIN_NV04(push, NV20_3D(TEX_ENABLE(i)), 1);
291 	PUSH_DATA (push, tx_enable);
292 
293 	context_dirty(ctx, TEX_SHADER);
294 }
295 
296 void
nv20_emit_tex_shader(struct gl_context * ctx,int emit)297 nv20_emit_tex_shader(struct gl_context *ctx, int emit)
298 {
299 	struct nouveau_pushbuf *push = context_push(ctx);
300 	uint32_t tx_shader_op = 0;
301 	int i;
302 
303 	for (i = 0; i < NV20_TEXTURE_UNITS; i++) {
304 		if (!ctx->Texture.Unit[i]._Current)
305 			continue;
306 
307 		tx_shader_op |= NV20_3D_TEX_SHADER_OP_TX0_TEXTURE_2D << 5 * i;
308 	}
309 
310 	BEGIN_NV04(push, NV20_3D(TEX_SHADER_OP), 1);
311 	PUSH_DATA (push, tx_shader_op);
312 }
313