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