Tizen 2.0 Release
[profile/ivi/osmesa.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 }