308c25fbe1bff2688cb2efb5964ca1dd949fd235
[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 pipe_viewport_state *vpt = &nvfx->viewport;
11
12 WAIT_RING(chan, 11);
13 if(nvfx->render_mode == HW) {
14 OUT_RING(chan, RING_3D(NV34TCL_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 OUT_RING(chan, RING_3D(0x1d78, 1));
24 OUT_RING(chan, 1);
25 } else {
26 OUT_RING(chan, RING_3D(NV34TCL_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 OUT_RING(chan, RING_3D(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 pipe_rasterizer_state *rast = &nvfx->rasterizer->pipe;
45 struct pipe_scissor_state *s = &nvfx->scissor;
46
47 if ((rast->scissor == 0 && nvfx->state.scissor_enabled == 0))
48 return;
49 nvfx->state.scissor_enabled = rast->scissor;
50
51 WAIT_RING(chan, 3);
52 OUT_RING(chan, RING_3D(NV34TCL_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 pipe_stencil_ref *sr = &nvfx->stencil_ref;
67
68 WAIT_RING(chan, 4);
69 OUT_RING(chan, RING_3D(NV34TCL_STENCIL_FRONT_FUNC_REF, 1));
70 OUT_RING(chan, sr->ref_value[0]);
71 OUT_RING(chan, RING_3D(NV34TCL_STENCIL_BACK_FUNC_REF, 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 pipe_blend_color *bcol = &nvfx->blend_colour;
80
81 WAIT_RING(chan, 2);
82 OUT_RING(chan, RING_3D(NV34TCL_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
94 WAIT_RING(chan, 33);
95 OUT_RING(chan, RING_3D(NV34TCL_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 unsigned value = nvfx->hw_fragprog->coord_conventions;
104 if(value & NV34TCL_COORD_CONVENTIONS_ORIGIN_INVERTED)
105 value |= nvfx->framebuffer.height << NV34TCL_COORD_CONVENTIONS_HEIGHT_SHIFT;
106
107 WAIT_RING(chan, 2);
108 OUT_RING(chan, RING_3D(NV34TCL_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 unsigned enables[7] =
117 {
118 0,
119 NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0,
120 NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1,
121 NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE2,
122 NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE2 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE3,
123 NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE2 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE3 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE4,
124 NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE0 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE1 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE2 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE3 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE4 | NV34TCL_VP_CLIP_PLANES_ENABLE_PLANE5,
125 };
126
127 if(!nvfx->use_vp_clipping)
128 {
129 WAIT_RING(chan, 2);
130 OUT_RING(chan, RING_3D(NV34TCL_VP_CLIP_PLANES_ENABLE, 1));
131 OUT_RING(chan, 0);
132
133 WAIT_RING(chan, 6 * 4 + 1);
134 OUT_RING(chan, RING_3D(NV34TCL_VP_CLIP_PLANE_A(0), nvfx->clip.nr * 4));
135 OUT_RINGp(chan, &nvfx->clip.ucp[0][0], nvfx->clip.nr * 4);
136 }
137
138 WAIT_RING(chan, 2);
139 OUT_RING(chan, RING_3D(NV34TCL_VP_CLIP_PLANES_ENABLE, 1));
140 OUT_RING(chan, enables[nvfx->clip.nr]);
141 }
142
143 static void
144 nvfx_vertprog_ucp_validate(struct nvfx_context* nvfx)
145 {
146 struct nouveau_channel* chan = nvfx->screen->base.channel;
147 unsigned i;
148 struct nvfx_vertex_program* vp = nvfx->vertprog;
149 if(nvfx->clip.nr != vp->clip_nr)
150 {
151 unsigned idx;
152 WAIT_RING(chan, 14);
153
154 /* remove last instruction bit */
155 if(vp->clip_nr >= 0)
156 {
157 idx = vp->nr_insns - 7 + vp->clip_nr;
158 OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_FROM_ID, 1));
159 OUT_RING(chan, vp->exec->start + idx);
160 OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_INST(0), 4));
161 OUT_RINGp (chan, vp->insns[idx].data, 4);
162 }
163
164 /* set last instruction bit */
165 idx = vp->nr_insns - 7 + nvfx->clip.nr;
166 OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_FROM_ID, 1));
167 OUT_RING(chan, vp->exec->start + idx);
168 OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_INST(0), 4));
169 OUT_RINGp(chan, vp->insns[idx].data, 3);
170 OUT_RING(chan, vp->insns[idx].data[3] | 1);
171 vp->clip_nr = nvfx->clip.nr;
172 }
173
174 // TODO: only do this for the ones changed
175 WAIT_RING(chan, 6 * 6);
176 for(i = 0; i < nvfx->clip.nr; ++i)
177 {
178 OUT_RING(chan, RING_3D(NV34TCL_VP_UPLOAD_CONST_ID, 5));
179 OUT_RING(chan, vp->data->start + i);
180 OUT_RINGp (chan, nvfx->clip.ucp[i], 4);
181 }
182 }
183
184 static boolean
185 nvfx_state_validate_common(struct nvfx_context *nvfx)
186 {
187 struct nouveau_channel* chan = nvfx->screen->base.channel;
188 unsigned dirty;
189 unsigned still_dirty = 0;
190 int new_fb_mode = -1; /* 1 = all swizzled, 0 = make all linear */
191 boolean flush_tex_cache = FALSE;
192 unsigned render_temps;
193
194 if(nvfx != nvfx->screen->cur_ctx)
195 {
196 nvfx->dirty = ~0;
197 nvfx->hw_vtxelt_nr = 16;
198 nvfx->hw_pointsprite_control = -1;
199 nvfx->hw_vp_output = -1;
200 nvfx->screen->cur_ctx = nvfx;
201 nvfx->relocs_needed = NVFX_RELOCATE_ALL;
202 }
203
204 /* These can trigger use the of 3D engine to copy temporaries.
205 * That will recurse here and thus dirty all 3D state, so we need to this before anything else, and in a loop..
206 * This converges to having clean temps, then binding both fragtexes and framebuffers.
207 */
208 while(nvfx->dirty & (NVFX_NEW_FB | NVFX_NEW_SAMPLER))
209 {
210 if(nvfx->dirty & NVFX_NEW_SAMPLER)
211 {
212 nvfx->dirty &=~ NVFX_NEW_SAMPLER;
213 nvfx_fragtex_validate(nvfx);
214
215 // TODO: only set this if really necessary
216 flush_tex_cache = TRUE;
217 }
218
219 if(nvfx->dirty & NVFX_NEW_FB)
220 {
221 nvfx->dirty &=~ NVFX_NEW_FB;
222 new_fb_mode = nvfx_framebuffer_prepare(nvfx);
223
224 // TODO: make sure this doesn't happen, i.e. fbs have matching formats
225 assert(new_fb_mode >= 0);
226 }
227 }
228
229 dirty = nvfx->dirty;
230
231 if(nvfx->render_mode == HW)
232 {
233 if(dirty & (NVFX_NEW_VERTPROG | NVFX_NEW_VERTCONST | NVFX_NEW_UCP))
234 {
235 if(!nvfx_vertprog_validate(nvfx))
236 return FALSE;
237 }
238
239 if(dirty & NVFX_NEW_ARRAYS)
240 {
241 if(!nvfx_vbo_validate(nvfx))
242 return FALSE;
243 }
244
245 if(dirty & NVFX_NEW_INDEX)
246 {
247 if(nvfx->use_index_buffer)
248 nvfx_idxbuf_validate(nvfx);
249 else
250 still_dirty = NVFX_NEW_INDEX;
251 }
252 }
253 else
254 {
255 /* TODO: this looks a bit misdesigned */
256 if(dirty & (NVFX_NEW_VERTPROG | NVFX_NEW_UCP))
257 nvfx_vertprog_validate(nvfx);
258
259 if(dirty & (NVFX_NEW_ARRAYS | NVFX_NEW_INDEX | NVFX_NEW_FRAGPROG))
260 nvfx_vtxfmt_validate(nvfx);
261 }
262
263 if(dirty & NVFX_NEW_RAST)
264 sb_emit(chan, nvfx->rasterizer->sb, nvfx->rasterizer->sb_len);
265
266 if(dirty & NVFX_NEW_SCISSOR)
267 nvfx_state_scissor_validate(nvfx);
268
269 if(dirty & NVFX_NEW_STIPPLE)
270 nvfx_state_stipple_validate(nvfx);
271
272 if(nvfx->dirty & NVFX_NEW_UCP)
273 nvfx_ucp_validate(nvfx);
274
275 if(nvfx->use_vp_clipping && (nvfx->dirty & (NVFX_NEW_UCP | NVFX_NEW_VERTPROG)))
276 nvfx_vertprog_ucp_validate(nvfx);
277
278 if(dirty & (NVFX_NEW_FRAGPROG | NVFX_NEW_FRAGCONST | NVFX_NEW_VERTPROG | NVFX_NEW_SPRITE))
279 {
280 nvfx_fragprog_validate(nvfx);
281 if(dirty & NVFX_NEW_FRAGPROG)
282 flush_tex_cache = TRUE; // TODO: do we need this?
283 }
284
285 if(nvfx->is_nv4x)
286 {
287 unsigned vp_output = nvfx->vertprog->or | nvfx->hw_fragprog->or;
288 vp_output |= (1 << (nvfx->clip.nr + 6)) - (1 << 6);
289
290 if(vp_output != nvfx->hw_vp_output)
291 {
292 WAIT_RING(chan, 2);
293 OUT_RING(chan, RING_3D(NV40TCL_VP_RESULT_EN, 1));
294 OUT_RING(chan, vp_output);
295 nvfx->hw_vp_output = vp_output;
296 }
297 }
298
299 if(new_fb_mode >= 0)
300 nvfx_framebuffer_validate(nvfx, new_fb_mode);
301
302 if(dirty & NVFX_NEW_BLEND)
303 sb_emit(chan, nvfx->blend->sb, nvfx->blend->sb_len);
304
305 if(dirty & NVFX_NEW_BCOL)
306 nvfx_state_blend_colour_validate(nvfx);
307
308 if(dirty & NVFX_NEW_ZSA)
309 sb_emit(chan, nvfx->zsa->sb, nvfx->zsa->sb_len);
310
311 if(dirty & NVFX_NEW_SR)
312 nvfx_state_sr_validate(nvfx);
313
314 /* All these dependencies are wrong, but otherwise
315 etracer, neverball, foobillard, glest totally misrender
316 TODO: find the right fix
317 */
318 if(dirty & (NVFX_NEW_VIEWPORT | NVFX_NEW_RAST | NVFX_NEW_ZSA) || (new_fb_mode >= 0))
319 {
320 nvfx_state_viewport_validate(nvfx);
321 }
322
323 if(dirty & NVFX_NEW_ZSA || (new_fb_mode >= 0))
324 {
325 WAIT_RING(chan, 3);
326 OUT_RING(chan, RING_3D(NV34TCL_DEPTH_WRITE_ENABLE, 2));
327 OUT_RING(chan, nvfx->framebuffer.zsbuf && nvfx->zsa->pipe.depth.writemask);
328 OUT_RING(chan, nvfx->framebuffer.zsbuf && nvfx->zsa->pipe.depth.enabled);
329 }
330
331 if((new_fb_mode >= 0) || (dirty & NVFX_NEW_FRAGPROG))
332 nvfx_coord_conventions_validate(nvfx);
333
334 if(flush_tex_cache)
335 {
336 // TODO: what about nv30?
337 if(nvfx->is_nv4x)
338 {
339 WAIT_RING(chan, 4);
340 OUT_RING(chan, RING_3D(NV40TCL_TEX_CACHE_CTL, 1));
341 OUT_RING(chan, 2);
342 OUT_RING(chan, RING_3D(NV40TCL_TEX_CACHE_CTL, 1));
343 OUT_RING(chan, 1);
344 }
345 }
346
347 nvfx->dirty = dirty & still_dirty;
348
349 render_temps = nvfx->state.render_temps;
350 if(render_temps)
351 {
352 for(int i = 0; i < nvfx->framebuffer.nr_cbufs; ++i)
353 {
354 if(render_temps & (1 << i)) {
355 assert(((struct nvfx_surface*)nvfx->framebuffer.cbufs[i])->temp);
356 util_dirty_surface_set_dirty(nvfx_surface_get_dirty_surfaces(nvfx->framebuffer.cbufs[i]),
357 (struct util_dirty_surface*)nvfx->framebuffer.cbufs[i]);
358 }
359 }
360
361 if(render_temps & 0x80) {
362 assert(((struct nvfx_surface*)nvfx->framebuffer.zsbuf)->temp);
363 util_dirty_surface_set_dirty(nvfx_surface_get_dirty_surfaces(nvfx->framebuffer.zsbuf),
364 (struct util_dirty_surface*)nvfx->framebuffer.zsbuf);
365 }
366 }
367
368 return TRUE;
369 }
370
371 inline void
372 nvfx_state_relocate(struct nvfx_context *nvfx, unsigned relocs)
373 {
374 struct nouveau_channel* chan = nvfx->screen->base.channel;
375 /* we need to ensure there is enough space to output relocations in one go */
376 const unsigned max_relocs = 0
377 + 16 /* vertex buffers, incl. dma flag */
378 + 2 /* index buffer plus format+dma flag */
379 + 2 * 5 /* 4 cbufs + zsbuf, plus dma objects */
380 + 2 * 16 /* fragment textures plus format+dma flag */
381 + 2 * 4 /* vertex textures plus format+dma flag */
382 + 1 /* fragprog incl dma flag */
383 ;
384
385 MARK_RING(chan, max_relocs * 2, max_relocs * 2);
386
387 if(relocs & NVFX_RELOCATE_FRAMEBUFFER)
388 nvfx_framebuffer_relocate(nvfx);
389 if(relocs & NVFX_RELOCATE_FRAGTEX)
390 nvfx_fragtex_relocate(nvfx);
391 if(relocs & NVFX_RELOCATE_FRAGPROG)
392 nvfx_fragprog_relocate(nvfx);
393 if(relocs & NVFX_RELOCATE_VTXBUF)
394 nvfx_vbo_relocate(nvfx);
395 if(relocs & NVFX_RELOCATE_IDXBUF)
396 nvfx_idxbuf_relocate(nvfx);
397 }
398
399 boolean
400 nvfx_state_validate(struct nvfx_context *nvfx)
401 {
402 boolean was_sw = nvfx->fallback_swtnl ? TRUE : FALSE;
403
404 if (nvfx->render_mode != HW) {
405 /* Don't even bother trying to go back to hw if none
406 * of the states that caused swtnl previously have changed.
407 */
408 if ((nvfx->fallback_swtnl & nvfx->dirty)
409 != nvfx->fallback_swtnl)
410 return FALSE;
411
412 /* Attempt to go to hwtnl again */
413 nvfx->dirty |= (NVFX_NEW_VIEWPORT |
414 NVFX_NEW_VERTPROG |
415 NVFX_NEW_ARRAYS);
416 nvfx->render_mode = HW;
417 }
418
419 if(!nvfx_state_validate_common(nvfx))
420 return FALSE;
421
422 return TRUE;
423 }
424
425 boolean
426 nvfx_state_validate_swtnl(struct nvfx_context *nvfx)
427 {
428 struct draw_context *draw = nvfx->draw;
429
430 /* Setup for swtnl */
431 if (nvfx->render_mode == HW) {
432 NOUVEAU_ERR("hw->swtnl 0x%08x\n", nvfx->fallback_swtnl);
433 nvfx->pipe.flush(&nvfx->pipe, 0, NULL);
434 nvfx->dirty |= (NVFX_NEW_VIEWPORT |
435 NVFX_NEW_VERTPROG |
436 NVFX_NEW_ARRAYS);
437 nvfx->render_mode = SWTNL;
438 }
439
440 if (nvfx->draw_dirty & NVFX_NEW_VERTPROG)
441 draw_bind_vertex_shader(draw, nvfx->vertprog->draw);
442
443 if (nvfx->draw_dirty & NVFX_NEW_RAST)
444 draw_set_rasterizer_state(draw, &nvfx->rasterizer->pipe,
445 nvfx->rasterizer);
446
447 if (nvfx->draw_dirty & NVFX_NEW_UCP)
448 draw_set_clip_state(draw, &nvfx->clip);
449
450 if (nvfx->draw_dirty & NVFX_NEW_VIEWPORT)
451 draw_set_viewport_state(draw, &nvfx->viewport);
452
453 if (nvfx->draw_dirty & NVFX_NEW_ARRAYS) {
454 draw_set_vertex_buffers(draw, nvfx->vtxbuf_nr, nvfx->vtxbuf);
455 draw_set_vertex_elements(draw, nvfx->vtxelt->num_elements, nvfx->vtxelt->pipe);
456 }
457
458 if (nvfx->draw_dirty & NVFX_NEW_INDEX)
459 draw_set_index_buffer(draw, &nvfx->idxbuf);
460
461 nvfx_state_validate_common(nvfx);
462
463 nvfx->draw_dirty = 0;
464 return TRUE;
465 }