nvfx: simplify and correct fragment program update logic
[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 static boolean
7 nvfx_state_validate_common(struct nvfx_context *nvfx)
8 {
9 struct nouveau_channel* chan = nvfx->screen->base.channel;
10 unsigned dirty;
11 unsigned still_dirty = 0;
12 int all_swizzled = -1;
13 boolean flush_tex_cache = FALSE;
14 unsigned render_temps;
15
16 if(nvfx != nvfx->screen->cur_ctx)
17 {
18 nvfx->dirty = ~0;
19 nvfx->hw_vtxelt_nr = 16;
20 nvfx->hw_pointsprite_control = -1;
21 nvfx->hw_vp_output = -1;
22 nvfx->screen->cur_ctx = nvfx;
23 }
24
25 /* These can trigger use the of 3D engine to copy temporaries.
26 * That will recurse here and thus dirty all 3D state, so we need to this before anything else, and in a loop..
27 * This converges to having clean temps, then binding both fragtexes and framebuffers.
28 */
29 while(nvfx->dirty & (NVFX_NEW_FB | NVFX_NEW_SAMPLER))
30 {
31 if(nvfx->dirty & NVFX_NEW_SAMPLER)
32 {
33 nvfx->dirty &=~ NVFX_NEW_SAMPLER;
34 nvfx_fragtex_validate(nvfx);
35
36 // TODO: only set this if really necessary
37 flush_tex_cache = TRUE;
38 }
39
40 if(nvfx->dirty & NVFX_NEW_FB)
41 {
42 nvfx->dirty &=~ NVFX_NEW_FB;
43 all_swizzled = nvfx_framebuffer_prepare(nvfx);
44
45 // TODO: make sure this doesn't happen, i.e. fbs have matching formats
46 assert(all_swizzled >= 0);
47 }
48 }
49
50 dirty = nvfx->dirty;
51
52 if(nvfx->render_mode == HW)
53 {
54 if(dirty & (NVFX_NEW_VERTPROG | NVFX_NEW_VERTCONST | NVFX_NEW_UCP))
55 {
56 if(!nvfx_vertprog_validate(nvfx))
57 return FALSE;
58 }
59
60 if(dirty & NVFX_NEW_ARRAYS)
61 {
62 if(!nvfx_vbo_validate(nvfx))
63 return FALSE;
64 }
65
66 if(dirty & NVFX_NEW_INDEX)
67 {
68 if(nvfx->use_index_buffer)
69 nvfx_idxbuf_validate(nvfx);
70 else
71 still_dirty = NVFX_NEW_INDEX;
72 }
73 }
74 else
75 {
76 /* TODO: this looks a bit misdesigned */
77 if(dirty & (NVFX_NEW_VERTPROG | NVFX_NEW_UCP))
78 nvfx_vertprog_validate(nvfx);
79
80 if(dirty & (NVFX_NEW_ARRAYS | NVFX_NEW_INDEX | NVFX_NEW_FRAGPROG))
81 nvfx_vtxfmt_validate(nvfx);
82 }
83
84 if(dirty & NVFX_NEW_RAST)
85 sb_emit(chan, nvfx->rasterizer->sb, nvfx->rasterizer->sb_len);
86
87 if(dirty & NVFX_NEW_SCISSOR)
88 nvfx_state_scissor_validate(nvfx);
89
90 if(dirty & NVFX_NEW_STIPPLE)
91 nvfx_state_stipple_validate(nvfx);
92
93 if(dirty & (NVFX_NEW_FRAGPROG | NVFX_NEW_FRAGCONST | NVFX_NEW_VERTPROG | NVFX_NEW_SPRITE))
94 {
95 nvfx_fragprog_validate(nvfx);
96 if(dirty & NVFX_NEW_FRAGPROG)
97 flush_tex_cache = TRUE; // TODO: do we need this?
98 }
99
100 if(all_swizzled >= 0)
101 nvfx_framebuffer_validate(nvfx, all_swizzled);
102
103 if(dirty & NVFX_NEW_BLEND)
104 sb_emit(chan, nvfx->blend->sb, nvfx->blend->sb_len);
105
106 if(dirty & NVFX_NEW_BCOL)
107 nvfx_state_blend_colour_validate(nvfx);
108
109 if(dirty & NVFX_NEW_ZSA)
110 sb_emit(chan, nvfx->zsa->sb, nvfx->zsa->sb_len);
111
112 if(dirty & NVFX_NEW_SR)
113 nvfx_state_sr_validate(nvfx);
114
115 /* All these dependencies are wrong, but otherwise
116 etracer, neverball, foobillard, glest totally misrender
117 TODO: find the right fix
118 */
119 if(dirty & (NVFX_NEW_VIEWPORT | NVFX_NEW_RAST | NVFX_NEW_ZSA) || (all_swizzled >= 0))
120 {
121 nvfx_state_viewport_validate(nvfx);
122 }
123
124 if(dirty & NVFX_NEW_ZSA || (all_swizzled >= 0))
125 {
126 WAIT_RING(chan, 3);
127 OUT_RING(chan, RING_3D(NV34TCL_DEPTH_WRITE_ENABLE, 2));
128 OUT_RING(chan, nvfx->framebuffer.zsbuf && nvfx->zsa->pipe.depth.writemask);
129 OUT_RING(chan, nvfx->framebuffer.zsbuf && nvfx->zsa->pipe.depth.enabled);
130 }
131
132 if(flush_tex_cache)
133 {
134 // TODO: what about nv30?
135 if(nvfx->is_nv4x)
136 {
137 WAIT_RING(chan, 4);
138 OUT_RING(chan, RING_3D(NV40TCL_TEX_CACHE_CTL, 1));
139 OUT_RING(chan, 2);
140 OUT_RING(chan, RING_3D(NV40TCL_TEX_CACHE_CTL, 1));
141 OUT_RING(chan, 1);
142 }
143 }
144
145 nvfx->dirty = dirty & still_dirty;
146
147 render_temps = nvfx->state.render_temps;
148 if(render_temps)
149 {
150 for(int i = 0; i < nvfx->framebuffer.nr_cbufs; ++i)
151 {
152 if(render_temps & (1 << i))
153 util_dirty_surface_set_dirty(nvfx_surface_get_dirty_surfaces(nvfx->framebuffer.cbufs[i]),
154 (struct util_dirty_surface*)nvfx->framebuffer.cbufs[i]);
155 }
156
157 if(render_temps & 0x80)
158 util_dirty_surface_set_dirty(nvfx_surface_get_dirty_surfaces(nvfx->framebuffer.zsbuf),
159 (struct util_dirty_surface*)nvfx->framebuffer.zsbuf);
160 }
161
162 return TRUE;
163 }
164
165 void
166 nvfx_state_emit(struct nvfx_context *nvfx)
167 {
168 struct nouveau_channel* chan = nvfx->screen->base.channel;
169 /* we need to ensure there is enough space to output relocations in one go */
170 unsigned max_relocs = 0
171 + 16 /* vertex buffers, incl. dma flag */
172 + 2 /* index buffer plus format+dma flag */
173 + 2 * 5 /* 4 cbufs + zsbuf, plus dma objects */
174 + 2 * 16 /* fragment textures plus format+dma flag */
175 + 2 * 4 /* vertex textures plus format+dma flag */
176 + 1 /* fragprog incl dma flag */
177 ;
178 MARK_RING(chan, max_relocs * 2, max_relocs * 2);
179 nvfx_state_relocate(nvfx);
180 }
181
182 void
183 nvfx_state_relocate(struct nvfx_context *nvfx)
184 {
185 nvfx_framebuffer_relocate(nvfx);
186 nvfx_fragtex_relocate(nvfx);
187 nvfx_fragprog_relocate(nvfx);
188 if (nvfx->render_mode == HW)
189 {
190 nvfx_vbo_relocate(nvfx);
191 if(nvfx->use_index_buffer)
192 nvfx_idxbuf_relocate(nvfx);
193 }
194 }
195
196 boolean
197 nvfx_state_validate(struct nvfx_context *nvfx)
198 {
199 boolean was_sw = nvfx->fallback_swtnl ? TRUE : FALSE;
200
201 if (nvfx->render_mode != HW) {
202 /* Don't even bother trying to go back to hw if none
203 * of the states that caused swtnl previously have changed.
204 */
205 if ((nvfx->fallback_swtnl & nvfx->dirty)
206 != nvfx->fallback_swtnl)
207 return FALSE;
208
209 /* Attempt to go to hwtnl again */
210 nvfx->dirty |= (NVFX_NEW_VIEWPORT |
211 NVFX_NEW_VERTPROG |
212 NVFX_NEW_ARRAYS);
213 nvfx->render_mode = HW;
214 }
215
216 if(!nvfx_state_validate_common(nvfx))
217 return FALSE;
218
219 if (was_sw)
220 NOUVEAU_ERR("swtnl->hw\n");
221
222 return TRUE;
223 }
224
225 boolean
226 nvfx_state_validate_swtnl(struct nvfx_context *nvfx)
227 {
228 struct draw_context *draw = nvfx->draw;
229
230 /* Setup for swtnl */
231 if (nvfx->render_mode == HW) {
232 NOUVEAU_ERR("hw->swtnl 0x%08x\n", nvfx->fallback_swtnl);
233 nvfx->pipe.flush(&nvfx->pipe, 0, NULL);
234 nvfx->dirty |= (NVFX_NEW_VIEWPORT |
235 NVFX_NEW_VERTPROG |
236 NVFX_NEW_ARRAYS);
237 nvfx->render_mode = SWTNL;
238 }
239
240 if (nvfx->draw_dirty & NVFX_NEW_VERTPROG)
241 draw_bind_vertex_shader(draw, nvfx->vertprog->draw);
242
243 if (nvfx->draw_dirty & NVFX_NEW_RAST)
244 draw_set_rasterizer_state(draw, &nvfx->rasterizer->pipe,
245 nvfx->rasterizer);
246
247 if (nvfx->draw_dirty & NVFX_NEW_UCP)
248 draw_set_clip_state(draw, &nvfx->clip);
249
250 if (nvfx->draw_dirty & NVFX_NEW_VIEWPORT)
251 draw_set_viewport_state(draw, &nvfx->viewport);
252
253 if (nvfx->draw_dirty & NVFX_NEW_ARRAYS) {
254 draw_set_vertex_buffers(draw, nvfx->vtxbuf_nr, nvfx->vtxbuf);
255 draw_set_vertex_elements(draw, nvfx->vtxelt->num_elements, nvfx->vtxelt->pipe);
256 }
257
258 nvfx_state_validate_common(nvfx);
259
260 nvfx->draw_dirty = 0;
261 return TRUE;
262 }