nvfx: fix nv3x fallout from state validation changes
[mesa.git] / src / gallium / drivers / nvfx / nvfx_state_emit.c
1 #include "nvfx_context.h"
2 #include "nvfx_state.h"
3 #include "nvfx_resource.h"
4 #include "draw/draw_context.h"
5
6 void
7 nvfx_state_viewport_validate(struct nvfx_context *nvfx)
8 {
9 struct nouveau_channel *chan = nvfx->screen->base.channel;
10 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
11 struct pipe_viewport_state *vpt = &nvfx->viewport;
12
13 if(nvfx->render_mode == HW) {
14 BEGIN_RING(chan, eng3d, NV30_3D_VIEWPORT_TRANSLATE_X, 8);
15 OUT_RINGf(chan, vpt->translate[0]);
16 OUT_RINGf(chan, vpt->translate[1]);
17 OUT_RINGf(chan, vpt->translate[2]);
18 OUT_RINGf(chan, vpt->translate[3]);
19 OUT_RINGf(chan, vpt->scale[0]);
20 OUT_RINGf(chan, vpt->scale[1]);
21 OUT_RINGf(chan, vpt->scale[2]);
22 OUT_RINGf(chan, vpt->scale[3]);
23 BEGIN_RING(chan, eng3d, 0x1d78, 1);
24 OUT_RING(chan, 1);
25 } else {
26 BEGIN_RING(chan, eng3d, NV30_3D_VIEWPORT_TRANSLATE_X, 8);
27 OUT_RINGf(chan, 0.0f);
28 OUT_RINGf(chan, 0.0f);
29 OUT_RINGf(chan, 0.0f);
30 OUT_RINGf(chan, 0.0f);
31 OUT_RINGf(chan, 1.0f);
32 OUT_RINGf(chan, 1.0f);
33 OUT_RINGf(chan, 1.0f);
34 OUT_RINGf(chan, 1.0f);
35 BEGIN_RING(chan, eng3d, 0x1d78, 1);
36 OUT_RING(chan, nvfx->is_nv4x ? 0x110 : 1);
37 }
38 }
39
40 void
41 nvfx_state_scissor_validate(struct nvfx_context *nvfx)
42 {
43 struct nouveau_channel *chan = nvfx->screen->base.channel;
44 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
45 struct pipe_rasterizer_state *rast = &nvfx->rasterizer->pipe;
46 struct pipe_scissor_state *s = &nvfx->scissor;
47
48 if ((rast->scissor == 0 && nvfx->state.scissor_enabled == 0))
49 return;
50 nvfx->state.scissor_enabled = rast->scissor;
51
52 BEGIN_RING(chan, eng3d, NV30_3D_SCISSOR_HORIZ, 2);
53 if (nvfx->state.scissor_enabled) {
54 OUT_RING(chan, ((s->maxx - s->minx) << 16) | s->minx);
55 OUT_RING(chan, ((s->maxy - s->miny) << 16) | s->miny);
56 } else {
57 OUT_RING(chan, 4096 << 16);
58 OUT_RING(chan, 4096 << 16);
59 }
60 }
61
62 void
63 nvfx_state_sr_validate(struct nvfx_context *nvfx)
64 {
65 struct nouveau_channel* chan = nvfx->screen->base.channel;
66 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
67 struct pipe_stencil_ref *sr = &nvfx->stencil_ref;
68
69 BEGIN_RING(chan, eng3d, NV30_3D_STENCIL_FUNC_REF(0), 1);
70 OUT_RING(chan, sr->ref_value[0]);
71 BEGIN_RING(chan, eng3d, NV30_3D_STENCIL_FUNC_REF(1), 1);
72 OUT_RING(chan, sr->ref_value[1]);
73 }
74
75 void
76 nvfx_state_blend_colour_validate(struct nvfx_context *nvfx)
77 {
78 struct nouveau_channel* chan = nvfx->screen->base.channel;
79 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
80 struct pipe_blend_color *bcol = &nvfx->blend_colour;
81
82 BEGIN_RING(chan, eng3d, NV30_3D_BLEND_COLOR, 1);
83 OUT_RING(chan, ((float_to_ubyte(bcol->color[3]) << 24) |
84 (float_to_ubyte(bcol->color[0]) << 16) |
85 (float_to_ubyte(bcol->color[1]) << 8) |
86 (float_to_ubyte(bcol->color[2]) << 0)));
87 }
88
89 void
90 nvfx_state_stipple_validate(struct nvfx_context *nvfx)
91 {
92 struct nouveau_channel *chan = nvfx->screen->base.channel;
93 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
94
95 BEGIN_RING(chan, eng3d, NV30_3D_POLYGON_STIPPLE_PATTERN(0), 32);
96 OUT_RINGp(chan, nvfx->stipple, 32);
97 }
98
99 static void
100 nvfx_coord_conventions_validate(struct nvfx_context* nvfx)
101 {
102 struct nouveau_channel* chan = nvfx->screen->base.channel;
103 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
104 unsigned value = nvfx->hw_fragprog->coord_conventions;
105 if(value & NV30_3D_COORD_CONVENTIONS_ORIGIN_INVERTED)
106 value |= nvfx->framebuffer.height << NV30_3D_COORD_CONVENTIONS_HEIGHT__SHIFT;
107
108 BEGIN_RING(chan, eng3d, NV30_3D_COORD_CONVENTIONS, 1);
109 OUT_RING(chan, value);
110 }
111
112 static void
113 nvfx_ucp_validate(struct nvfx_context* nvfx)
114 {
115 struct nouveau_channel* chan = nvfx->screen->base.channel;
116 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
117 unsigned enables[] =
118 {
119 NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE0,
120 NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE1,
121 NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE2,
122 NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE3,
123 NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE4,
124 NV30_3D_VP_CLIP_PLANES_ENABLE_PLANE5
125 };
126 unsigned i, enable = 0, nr = 0;
127
128 for (i = 0; i < 6; i++) {
129 if (nvfx->rasterizer->pipe.clip_plane_enable & (1 << i)) {
130 enable |= enables[i];
131 nr = i+1;
132 }
133 }
134
135 if(!nvfx->use_vp_clipping)
136 {
137 BEGIN_RING(chan, eng3d, NV30_3D_VP_CLIP_PLANES_ENABLE, 1);
138 OUT_RING(chan, 0);
139
140 BEGIN_RING(chan, eng3d, NV30_3D_VP_CLIP_PLANE(0, 0),
141 nr * 4);
142 OUT_RINGp(chan, &nvfx->clip.ucp[0][0], nr * 4);
143 }
144
145 BEGIN_RING(chan, eng3d, NV30_3D_VP_CLIP_PLANES_ENABLE, 1);
146 OUT_RING(chan, enable);
147 }
148
149 static void
150 nvfx_vertprog_ucp_validate(struct nvfx_context* nvfx)
151 {
152 struct nouveau_channel* chan = nvfx->screen->base.channel;
153 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
154 unsigned i;
155 struct nvfx_vertex_program* vp = nvfx->hw_vertprog;
156 unsigned enable = nvfx->rasterizer->pipe.clip_plane_enable;
157 unsigned nr = util_bitcount(enable);
158
159 if(nr != vp->clip_nr)
160 {
161 unsigned idx;
162
163 /* remove last instruction bit */
164 if(vp->clip_nr >= 0)
165 {
166 idx = vp->nr_insns - 7 + vp->clip_nr;
167 BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_FROM_ID, 1);
168 OUT_RING(chan, vp->exec->start + idx);
169 BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_INST(0), 4);
170 OUT_RINGp (chan, vp->insns[idx].data, 4);
171 }
172
173 /* set last instruction bit */
174 idx = vp->nr_insns - 7 + nr;
175 BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_FROM_ID, 1);
176 OUT_RING(chan, vp->exec->start + idx);
177 BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_INST(0), 4);
178 OUT_RINGp(chan, vp->insns[idx].data, 3);
179 OUT_RING(chan, vp->insns[idx].data[3] | 1);
180 vp->clip_nr = nr;
181 }
182
183 // TODO: only do this for the ones changed
184 for(i = 0; enable; ++i)
185 {
186 unsigned index = ffs(enable) - 1;
187 enable &= ~(1 << index);
188
189 BEGIN_RING(chan, eng3d, NV30_3D_VP_UPLOAD_CONST_ID, 5);
190 OUT_RING(chan, vp->data->start + i);
191 OUT_RINGp (chan, nvfx->clip.ucp[index], 4);
192 }
193 }
194
195 static boolean
196 nvfx_state_validate_common(struct nvfx_context *nvfx)
197 {
198 struct nouveau_channel* chan = nvfx->screen->base.channel;
199 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
200 unsigned dirty;
201 unsigned still_dirty = 0;
202 boolean flush_tex_cache = FALSE;
203
204 if(nvfx != nvfx->screen->cur_ctx)
205 {
206 nvfx->dirty = ~0;
207 nvfx->hw_vtxelt_nr = 16;
208 nvfx->hw_pointsprite_control = -1;
209 nvfx->hw_vp_output = -1;
210 nvfx->screen->cur_ctx = nvfx;
211 nvfx->relocs_needed = NVFX_RELOCATE_ALL;
212 }
213
214 dirty = nvfx->dirty;
215
216 if(nvfx->render_mode == HW)
217 {
218 if(dirty & (NVFX_NEW_VERTPROG | NVFX_NEW_VERTCONST))
219 {
220 if(!nvfx_vertprog_validate(nvfx))
221 return FALSE;
222 }
223
224 if(dirty & NVFX_NEW_ARRAYS)
225 {
226 if(!nvfx_vbo_validate(nvfx))
227 return FALSE;
228 }
229
230 if(dirty & NVFX_NEW_INDEX)
231 {
232 if(nvfx->use_index_buffer)
233 nvfx_idxbuf_validate(nvfx);
234 else
235 still_dirty = NVFX_NEW_INDEX;
236 }
237 }
238 else
239 {
240 if(dirty & NVFX_NEW_VERTPROG) {
241 assert(nvfx_vertprog_validate(nvfx));
242 nvfx_vbo_swtnl_validate(nvfx);
243 }
244 }
245
246 if(dirty & NVFX_NEW_SAMPLER) {
247 /* XXX: we take the big hammer here, I have no idea why this is needed
248 to make this work properly */
249 nvfx->dirty &= ~NVFX_NEW_SAMPLER;
250 nvfx_fragtex_validate(nvfx);
251
252 // TODO: only set this if really necessary
253 flush_tex_cache = TRUE;
254 }
255
256 if(dirty & NVFX_NEW_RAST)
257 sb_emit(chan, nvfx->rasterizer->sb, nvfx->rasterizer->sb_len);
258
259 if(dirty & NVFX_NEW_SCISSOR)
260 nvfx_state_scissor_validate(nvfx);
261
262 if(dirty & NVFX_NEW_STIPPLE)
263 nvfx_state_stipple_validate(nvfx);
264
265 if(nvfx->dirty & (NVFX_NEW_UCP | NVFX_NEW_RAST))
266 nvfx_ucp_validate(nvfx);
267
268 if(nvfx->use_vp_clipping && (nvfx->dirty &
269 (NVFX_NEW_UCP | NVFX_NEW_VERTPROG |
270 NVFX_NEW_RAST)))
271 nvfx_vertprog_ucp_validate(nvfx);
272
273 if(dirty & (NVFX_NEW_FRAGPROG | NVFX_NEW_FRAGCONST |
274 NVFX_NEW_VERTPROG | NVFX_NEW_SPRITE))
275 {
276 nvfx_fragprog_validate(nvfx);
277 if(dirty & NVFX_NEW_FRAGPROG)
278 flush_tex_cache = TRUE; // TODO: do we need this?
279 }
280
281 if(nvfx->is_nv4x)
282 {
283 unsigned vp_output = nvfx->hw_vertprog->or | nvfx->hw_fragprog->or;
284 vp_output |= ((1 << (nvfx->rasterizer->pipe.clip_plane_enable & 63)) - 1) << 6;
285
286 if(vp_output != nvfx->hw_vp_output)
287 {
288 BEGIN_RING(chan, eng3d, NV40_3D_VP_RESULT_EN, 1);
289 OUT_RING(chan, vp_output);
290 nvfx->hw_vp_output = vp_output;
291 }
292 }
293
294 if(dirty & NVFX_NEW_FB)
295 nvfx_framebuffer_validate(nvfx);
296
297 if(dirty & NVFX_NEW_BLEND)
298 sb_emit(chan, nvfx->blend->sb, nvfx->blend->sb_len);
299
300 if(dirty & NVFX_NEW_BCOL)
301 nvfx_state_blend_colour_validate(nvfx);
302
303 if(dirty & NVFX_NEW_ZSA)
304 sb_emit(chan, nvfx->zsa->sb, nvfx->zsa->sb_len);
305
306 if(dirty & NVFX_NEW_SR)
307 nvfx_state_sr_validate(nvfx);
308
309 /* XXX: nv3x needs viewport revalidation after RAST or ZSA change */
310 if(dirty & (NVFX_NEW_VIEWPORT | NVFX_NEW_RAST | NVFX_NEW_ZSA))
311 {
312 nvfx_state_viewport_validate(nvfx);
313 }
314
315 if(dirty & (NVFX_NEW_ZSA | NVFX_NEW_FB))
316 {
317 BEGIN_RING(chan, eng3d, NV30_3D_DEPTH_WRITE_ENABLE, 2);
318 OUT_RING(chan, nvfx->framebuffer.zsbuf &&
319 nvfx->zsa->pipe.depth.writemask);
320 OUT_RING(chan, nvfx->framebuffer.zsbuf &&
321 nvfx->zsa->pipe.depth.enabled);
322 }
323
324 if(dirty & (NVFX_NEW_FRAGPROG | NVFX_NEW_FB))
325 nvfx_coord_conventions_validate(nvfx);
326
327 if(flush_tex_cache && nvfx->is_nv4x)
328 {
329 BEGIN_RING(chan, eng3d, NV40_3D_TEX_CACHE_CTL, 1);
330 OUT_RING(chan, 2);
331 BEGIN_RING(chan, eng3d, NV40_3D_TEX_CACHE_CTL, 1);
332 OUT_RING(chan, 1);
333 }
334
335 nvfx->dirty = dirty & still_dirty;
336
337 return TRUE;
338 }
339
340 inline void
341 nvfx_state_relocate(struct nvfx_context *nvfx, unsigned relocs)
342 {
343 struct nouveau_channel* chan = nvfx->screen->base.channel;
344 /* we need to ensure there is enough space to output relocations in one go */
345 const unsigned max_relocs = 0
346 + 16 /* vertex buffers, incl. dma flag */
347 + 2 /* index buffer plus format+dma flag */
348 + 2 * 5 /* 4 cbufs + zsbuf, plus dma objects */
349 + 2 * 16 /* fragment textures plus format+dma flag */
350 + 2 * 4 /* vertex textures plus format+dma flag */
351 + 1 /* fragprog incl dma flag */
352 ;
353
354 MARK_RING(chan, max_relocs * 2, max_relocs * 2);
355
356 if(relocs & NVFX_RELOCATE_FRAMEBUFFER)
357 nvfx_framebuffer_relocate(nvfx);
358 if(relocs & NVFX_RELOCATE_FRAGTEX)
359 nvfx_fragtex_relocate(nvfx);
360 if(relocs & NVFX_RELOCATE_FRAGPROG)
361 nvfx_fragprog_relocate(nvfx);
362 if(relocs & NVFX_RELOCATE_VTXBUF)
363 nvfx_vbo_relocate(nvfx);
364 if(relocs & NVFX_RELOCATE_IDXBUF)
365 nvfx_idxbuf_relocate(nvfx);
366 }
367
368 boolean
369 nvfx_state_validate(struct nvfx_context *nvfx)
370 {
371 if (nvfx->render_mode != HW) {
372 /* Don't even bother trying to go back to hw if none
373 * of the states that caused swtnl previously have changed.
374 */
375 if ((nvfx->fallback_swtnl & nvfx->dirty)
376 != nvfx->fallback_swtnl)
377 return FALSE;
378
379 /* Attempt to go to hwtnl again */
380 nvfx->dirty |= (NVFX_NEW_VIEWPORT |
381 NVFX_NEW_VERTPROG |
382 NVFX_NEW_ARRAYS);
383 nvfx->render_mode = HW;
384 }
385
386 if(!nvfx_state_validate_common(nvfx))
387 return FALSE;
388
389 return TRUE;
390 }
391
392 boolean
393 nvfx_state_validate_swtnl(struct nvfx_context *nvfx)
394 {
395 struct draw_context *draw = nvfx->draw;
396
397 /* Setup for swtnl */
398 if (nvfx->render_mode == HW) {
399 static boolean warned = FALSE;
400 if(!warned) {
401 NOUVEAU_ERR("hw->swtnl 0x%08x\n", nvfx->fallback_swtnl);
402 warned = TRUE;
403 }
404 nvfx->pipe.flush(&nvfx->pipe, NULL);
405 nvfx->dirty |= (NVFX_NEW_VIEWPORT |
406 NVFX_NEW_VERTPROG |
407 NVFX_NEW_ARRAYS);
408 nvfx->render_mode = SWTNL;
409 }
410
411 if (nvfx->draw_dirty & NVFX_NEW_VERTPROG) {
412 if(!nvfx->vertprog->draw_vs)
413 nvfx->vertprog->draw_vs = draw_create_vertex_shader(draw, &nvfx->vertprog->pipe);
414 draw_bind_vertex_shader(draw, nvfx->vertprog->draw_vs);
415 }
416
417 if (nvfx->draw_dirty & NVFX_NEW_RAST)
418 draw_set_rasterizer_state(draw, &nvfx->rasterizer->pipe,
419 nvfx->rasterizer);
420
421 if (nvfx->draw_dirty & NVFX_NEW_UCP)
422 draw_set_clip_state(draw, &nvfx->clip);
423
424 if (nvfx->draw_dirty & NVFX_NEW_VIEWPORT)
425 draw_set_viewport_state(draw, &nvfx->viewport);
426
427 if (nvfx->draw_dirty & NVFX_NEW_ARRAYS) {
428 draw_set_vertex_buffers(draw, nvfx->vtxbuf_nr, nvfx->vtxbuf);
429 draw_set_vertex_elements(draw, nvfx->vtxelt->num_elements, nvfx->vtxelt->pipe);
430 }
431
432 if (nvfx->draw_dirty & NVFX_NEW_INDEX)
433 draw_set_index_buffer(draw, &nvfx->idxbuf);
434
435 nvfx_state_validate_common(nvfx);
436
437 nvfx->draw_dirty = 0;
438 return TRUE;
439 }