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