1
2#include "util/u_viewport.h"
3
4#include "nv50/nv50_context.h"
5
6static inline void
7nv50_fb_set_null_rt(struct nouveau_pushbuf *push, unsigned i)
8{
9   BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(i)), 4);
10   PUSH_DATA (push, 0);
11   PUSH_DATA (push, 0);
12   PUSH_DATA (push, 0);
13   PUSH_DATA (push, 0);
14   BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2);
15   PUSH_DATA (push, 64);
16   PUSH_DATA (push, 0);
17}
18
19static void
20nv50_validate_fb(struct nv50_context *nv50)
21{
22   struct nouveau_pushbuf *push = nv50->base.pushbuf;
23   struct pipe_framebuffer_state *fb = &nv50->framebuffer;
24   unsigned i;
25   unsigned ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1;
26   uint32_t array_size = 0xffff, array_mode = 0;
27
28   nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_FB);
29
30   BEGIN_NV04(push, NV50_3D(RT_CONTROL), 1);
31   PUSH_DATA (push, (076543210 << 4) | fb->nr_cbufs);
32   BEGIN_NV04(push, NV50_3D(SCREEN_SCISSOR_HORIZ), 2);
33   PUSH_DATA (push, fb->width << 16);
34   PUSH_DATA (push, fb->height << 16);
35
36   for (i = 0; i < fb->nr_cbufs; ++i) {
37      struct nv50_miptree *mt;
38      struct nv50_surface *sf;
39      struct nouveau_bo *bo;
40
41      if (!fb->cbufs[i]) {
42         nv50_fb_set_null_rt(push, i);
43         continue;
44      }
45
46      mt = nv50_miptree(fb->cbufs[i]->texture);
47      sf = nv50_surface(fb->cbufs[i]);
48      bo = mt->base.bo;
49
50      array_size = MIN2(array_size, sf->depth);
51      if (mt->layout_3d)
52         array_mode = NV50_3D_RT_ARRAY_MODE_MODE_3D; /* 1 << 16 */
53
54      /* can't mix 3D with ARRAY or have RTs of different depth/array_size */
55      assert(mt->layout_3d || !array_mode || array_size == 1);
56
57      BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(i)), 5);
58      PUSH_DATAh(push, mt->base.address + sf->offset);
59      PUSH_DATA (push, mt->base.address + sf->offset);
60      PUSH_DATA (push, nv50_format_table[sf->base.format].rt);
61      if (likely(nouveau_bo_memtype(bo))) {
62         assert(sf->base.texture->target != PIPE_BUFFER);
63
64         PUSH_DATA (push, mt->level[sf->base.u.tex.level].tile_mode);
65         PUSH_DATA (push, mt->layer_stride >> 2);
66         BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2);
67         PUSH_DATA (push, sf->width);
68         PUSH_DATA (push, sf->height);
69         BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1);
70         PUSH_DATA (push, array_mode | array_size);
71         nv50->rt_array_mode = array_mode | array_size;
72      } else {
73         PUSH_DATA (push, 0);
74         PUSH_DATA (push, 0);
75         BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2);
76         PUSH_DATA (push, NV50_3D_RT_HORIZ_LINEAR | mt->level[0].pitch);
77         PUSH_DATA (push, sf->height);
78         BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1);
79         PUSH_DATA (push, 0);
80
81         assert(!fb->zsbuf);
82         assert(!mt->ms_mode);
83      }
84
85      ms_mode = mt->ms_mode;
86
87      if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
88         nv50->state.rt_serialize = true;
89      mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
90      mt->base.status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING;
91
92      /* only register for writing, otherwise we'd always serialize here */
93      BCTX_REFN(nv50->bufctx_3d, 3D_FB, &mt->base, WR);
94   }
95
96   if (fb->zsbuf) {
97      struct nv50_miptree *mt = nv50_miptree(fb->zsbuf->texture);
98      struct nv50_surface *sf = nv50_surface(fb->zsbuf);
99      int unk = mt->base.base.target == PIPE_TEXTURE_3D || sf->depth == 1;
100
101      BEGIN_NV04(push, NV50_3D(ZETA_ADDRESS_HIGH), 5);
102      PUSH_DATAh(push, mt->base.address + sf->offset);
103      PUSH_DATA (push, mt->base.address + sf->offset);
104      PUSH_DATA (push, nv50_format_table[fb->zsbuf->format].rt);
105      PUSH_DATA (push, mt->level[sf->base.u.tex.level].tile_mode);
106      PUSH_DATA (push, mt->layer_stride >> 2);
107      BEGIN_NV04(push, NV50_3D(ZETA_ENABLE), 1);
108      PUSH_DATA (push, 1);
109      BEGIN_NV04(push, NV50_3D(ZETA_HORIZ), 3);
110      PUSH_DATA (push, sf->width);
111      PUSH_DATA (push, sf->height);
112      PUSH_DATA (push, (unk << 16) | sf->depth);
113
114      ms_mode = mt->ms_mode;
115
116      if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
117         nv50->state.rt_serialize = true;
118      mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
119      mt->base.status &= ~NOUVEAU_BUFFER_STATUS_GPU_READING;
120
121      BCTX_REFN(nv50->bufctx_3d, 3D_FB, &mt->base, WR);
122   } else {
123      BEGIN_NV04(push, NV50_3D(ZETA_ENABLE), 1);
124      PUSH_DATA (push, 0);
125   }
126
127   BEGIN_NV04(push, NV50_3D(MULTISAMPLE_MODE), 1);
128   PUSH_DATA (push, ms_mode);
129
130   /* Only need to initialize the first viewport, which is used for clears */
131   BEGIN_NV04(push, NV50_3D(VIEWPORT_HORIZ(0)), 2);
132   PUSH_DATA (push, fb->width << 16);
133   PUSH_DATA (push, fb->height << 16);
134
135   if (nv50->screen->tesla->oclass >= NVA3_3D_CLASS) {
136      unsigned ms = 1 << ms_mode;
137      BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
138      PUSH_DATA (push, (NV50_CB_AUX_SAMPLE_OFFSET << (8 - 2)) | NV50_CB_AUX);
139      BEGIN_NI04(push, NV50_3D(CB_DATA(0)), 2 * ms);
140      for (i = 0; i < ms; i++) {
141         float xy[2];
142         nv50->base.pipe.get_sample_position(&nv50->base.pipe, ms, i, xy);
143         PUSH_DATAf(push, xy[0]);
144         PUSH_DATAf(push, xy[1]);
145      }
146   }
147}
148
149static void
150nv50_validate_blend_colour(struct nv50_context *nv50)
151{
152   struct nouveau_pushbuf *push = nv50->base.pushbuf;
153
154   BEGIN_NV04(push, NV50_3D(BLEND_COLOR(0)), 4);
155   PUSH_DATAf(push, nv50->blend_colour.color[0]);
156   PUSH_DATAf(push, nv50->blend_colour.color[1]);
157   PUSH_DATAf(push, nv50->blend_colour.color[2]);
158   PUSH_DATAf(push, nv50->blend_colour.color[3]);
159}
160
161static void
162nv50_validate_stencil_ref(struct nv50_context *nv50)
163{
164   struct nouveau_pushbuf *push = nv50->base.pushbuf;
165
166   BEGIN_NV04(push, NV50_3D(STENCIL_FRONT_FUNC_REF), 1);
167   PUSH_DATA (push, nv50->stencil_ref.ref_value[0]);
168   BEGIN_NV04(push, NV50_3D(STENCIL_BACK_FUNC_REF), 1);
169   PUSH_DATA (push, nv50->stencil_ref.ref_value[1]);
170}
171
172static void
173nv50_validate_stipple(struct nv50_context *nv50)
174{
175   struct nouveau_pushbuf *push = nv50->base.pushbuf;
176   unsigned i;
177
178   BEGIN_NV04(push, NV50_3D(POLYGON_STIPPLE_PATTERN(0)), 32);
179   for (i = 0; i < 32; ++i)
180      PUSH_DATA(push, util_bswap32(nv50->stipple.stipple[i]));
181}
182
183static void
184nv50_validate_scissor(struct nv50_context *nv50)
185{
186   struct nouveau_pushbuf *push = nv50->base.pushbuf;
187#ifdef NV50_SCISSORS_CLIPPING
188   int minx, maxx, miny, maxy, i;
189   bool rast_scissor = nv50->rast ? nv50->rast->pipe.scissor : false;
190
191   if (!(nv50->dirty_3d &
192         (NV50_NEW_3D_SCISSOR | NV50_NEW_3D_VIEWPORT | NV50_NEW_3D_FRAMEBUFFER)) &&
193       nv50->state.scissor == rast_scissor)
194      return;
195
196   if (nv50->state.scissor != rast_scissor)
197      nv50->scissors_dirty = (1 << NV50_MAX_VIEWPORTS) - 1;
198
199   nv50->state.scissor = rast_scissor;
200
201   if ((nv50->dirty_3d & NV50_NEW_3D_FRAMEBUFFER) && !nv50->state.scissor)
202      nv50->scissors_dirty = (1 << NV50_MAX_VIEWPORTS) - 1;
203
204   for (i = 0; i < NV50_MAX_VIEWPORTS; i++) {
205      struct pipe_scissor_state *s = &nv50->scissors[i];
206      struct pipe_viewport_state *vp = &nv50->viewports[i];
207
208      if (!(nv50->scissors_dirty & (1 << i)) &&
209          !(nv50->viewports_dirty & (1 << i)))
210         continue;
211
212      if (nv50->state.scissor) {
213         minx = s->minx;
214         maxx = s->maxx;
215         miny = s->miny;
216         maxy = s->maxy;
217      } else {
218         minx = 0;
219         maxx = nv50->framebuffer.width;
220         miny = 0;
221         maxy = nv50->framebuffer.height;
222      }
223
224      minx = MAX2(minx, (int)(vp->translate[0] - fabsf(vp->scale[0])));
225      maxx = MIN2(maxx, (int)(vp->translate[0] + fabsf(vp->scale[0])));
226      miny = MAX2(miny, (int)(vp->translate[1] - fabsf(vp->scale[1])));
227      maxy = MIN2(maxy, (int)(vp->translate[1] + fabsf(vp->scale[1])));
228
229      minx = MIN2(minx, 8192);
230      maxx = MAX2(maxx, 0);
231      miny = MIN2(miny, 8192);
232      maxy = MAX2(maxy, 0);
233
234      BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(i)), 2);
235      PUSH_DATA (push, (maxx << 16) | minx);
236      PUSH_DATA (push, (maxy << 16) | miny);
237#else
238      BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(i)), 2);
239      PUSH_DATA (push, (s->maxx << 16) | s->minx);
240      PUSH_DATA (push, (s->maxy << 16) | s->miny);
241#endif
242   }
243
244   nv50->scissors_dirty = 0;
245}
246
247static void
248nv50_validate_viewport(struct nv50_context *nv50)
249{
250   struct nouveau_pushbuf *push = nv50->base.pushbuf;
251   float zmin, zmax;
252   int i;
253
254   for (i = 0; i < NV50_MAX_VIEWPORTS; i++) {
255      struct pipe_viewport_state *vpt = &nv50->viewports[i];
256
257      if (!(nv50->viewports_dirty & (1 << i)))
258         continue;
259
260      BEGIN_NV04(push, NV50_3D(VIEWPORT_TRANSLATE_X(i)), 3);
261      PUSH_DATAf(push, vpt->translate[0]);
262      PUSH_DATAf(push, vpt->translate[1]);
263      PUSH_DATAf(push, vpt->translate[2]);
264      BEGIN_NV04(push, NV50_3D(VIEWPORT_SCALE_X(i)), 3);
265      PUSH_DATAf(push, vpt->scale[0]);
266      PUSH_DATAf(push, vpt->scale[1]);
267      PUSH_DATAf(push, vpt->scale[2]);
268
269      /* If the halfz setting ever changes, the viewports will also get
270       * updated. The rast will get updated before the validate function has a
271       * chance to hit, so we can just use it directly without an atom
272       * dependency.
273       */
274      util_viewport_zmin_zmax(vpt, nv50->rast->pipe.clip_halfz, &zmin, &zmax);
275
276#ifdef NV50_SCISSORS_CLIPPING
277      BEGIN_NV04(push, NV50_3D(DEPTH_RANGE_NEAR(i)), 2);
278      PUSH_DATAf(push, zmin);
279      PUSH_DATAf(push, zmax);
280#endif
281   }
282
283   nv50->viewports_dirty = 0;
284}
285
286static void
287nv50_validate_window_rects(struct nv50_context *nv50)
288{
289   struct nouveau_pushbuf *push = nv50->base.pushbuf;
290   bool enable = nv50->window_rect.rects > 0 || nv50->window_rect.inclusive;
291   int i;
292
293   BEGIN_NV04(push, NV50_3D(CLIP_RECTS_EN), 1);
294   PUSH_DATA (push, enable);
295   if (!enable)
296      return;
297
298   BEGIN_NV04(push, NV50_3D(CLIP_RECTS_MODE), 1);
299   PUSH_DATA (push, !nv50->window_rect.inclusive);
300   BEGIN_NV04(push, NV50_3D(CLIP_RECT_HORIZ(0)), NV50_MAX_WINDOW_RECTANGLES * 2);
301   for (i = 0; i < nv50->window_rect.rects; i++) {
302      struct pipe_scissor_state *s = &nv50->window_rect.rect[i];
303      PUSH_DATA(push, (s->maxx << 16) | s->minx);
304      PUSH_DATA(push, (s->maxy << 16) | s->miny);
305   }
306   for (; i < NV50_MAX_WINDOW_RECTANGLES; i++) {
307      PUSH_DATA(push, 0);
308      PUSH_DATA(push, 0);
309   }
310}
311
312static inline void
313nv50_check_program_ucps(struct nv50_context *nv50,
314                        struct nv50_program *vp, uint8_t mask)
315{
316   const unsigned n = util_logbase2(mask) + 1;
317
318   if (vp->vp.clpd_nr >= n)
319      return;
320   nv50_program_destroy(nv50, vp);
321
322   vp->vp.clpd_nr = n;
323   if (likely(vp == nv50->vertprog)) {
324      nv50->dirty_3d |= NV50_NEW_3D_VERTPROG;
325      nv50_vertprog_validate(nv50);
326   } else {
327      nv50->dirty_3d |= NV50_NEW_3D_GMTYPROG;
328      nv50_gmtyprog_validate(nv50);
329   }
330   nv50_fp_linkage_validate(nv50);
331}
332
333/* alpha test is disabled if there are no color RTs, so make sure we have at
334 * least one if alpha test is enabled. Note that this must run after
335 * nv50_validate_fb, otherwise that will override the RT count setting.
336 */
337static void
338nv50_validate_derived_2(struct nv50_context *nv50)
339{
340   struct nouveau_pushbuf *push = nv50->base.pushbuf;
341
342   if (nv50->zsa && nv50->zsa->pipe.alpha_enabled &&
343       nv50->framebuffer.nr_cbufs == 0) {
344      nv50_fb_set_null_rt(push, 0);
345      BEGIN_NV04(push, NV50_3D(RT_CONTROL), 1);
346      PUSH_DATA (push, (076543210 << 4) | 1);
347   }
348}
349
350static void
351nv50_validate_clip(struct nv50_context *nv50)
352{
353   struct nouveau_pushbuf *push = nv50->base.pushbuf;
354   struct nv50_program *vp;
355   uint8_t clip_enable = nv50->rast->pipe.clip_plane_enable;
356
357   if (nv50->dirty_3d & NV50_NEW_3D_CLIP) {
358      BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
359      PUSH_DATA (push, NV50_CB_AUX_UCP_OFFSET << (8 - 2) | NV50_CB_AUX);
360      BEGIN_NI04(push, NV50_3D(CB_DATA(0)), PIPE_MAX_CLIP_PLANES * 4);
361      PUSH_DATAp(push, &nv50->clip.ucp[0][0], PIPE_MAX_CLIP_PLANES * 4);
362   }
363
364   vp = nv50->gmtyprog;
365   if (likely(!vp))
366      vp = nv50->vertprog;
367
368   if (clip_enable)
369      nv50_check_program_ucps(nv50, vp, clip_enable);
370
371   clip_enable &= vp->vp.clip_enable;
372   clip_enable |= vp->vp.cull_enable;
373
374   BEGIN_NV04(push, NV50_3D(CLIP_DISTANCE_ENABLE), 1);
375   PUSH_DATA (push, clip_enable);
376
377   if (nv50->state.clip_mode != vp->vp.clip_mode) {
378      nv50->state.clip_mode = vp->vp.clip_mode;
379      BEGIN_NV04(push, NV50_3D(CLIP_DISTANCE_MODE), 1);
380      PUSH_DATA (push, vp->vp.clip_mode);
381   }
382}
383
384static void
385nv50_validate_blend(struct nv50_context *nv50)
386{
387   struct nouveau_pushbuf *push = nv50->base.pushbuf;
388
389   PUSH_SPACE(push, nv50->blend->size);
390   PUSH_DATAp(push, nv50->blend->state, nv50->blend->size);
391}
392
393static void
394nv50_validate_zsa(struct nv50_context *nv50)
395{
396   struct nouveau_pushbuf *push = nv50->base.pushbuf;
397
398   PUSH_SPACE(push, nv50->zsa->size);
399   PUSH_DATAp(push, nv50->zsa->state, nv50->zsa->size);
400}
401
402static void
403nv50_validate_rasterizer(struct nv50_context *nv50)
404{
405   struct nouveau_pushbuf *push = nv50->base.pushbuf;
406
407   PUSH_SPACE(push, nv50->rast->size);
408   PUSH_DATAp(push, nv50->rast->state, nv50->rast->size);
409}
410
411static void
412nv50_validate_sample_mask(struct nv50_context *nv50)
413{
414   struct nouveau_pushbuf *push = nv50->base.pushbuf;
415
416   unsigned mask[4] =
417   {
418      nv50->sample_mask & 0xffff,
419      nv50->sample_mask & 0xffff,
420      nv50->sample_mask & 0xffff,
421      nv50->sample_mask & 0xffff
422   };
423
424   BEGIN_NV04(push, NV50_3D(MSAA_MASK(0)), 4);
425   PUSH_DATA (push, mask[0]);
426   PUSH_DATA (push, mask[1]);
427   PUSH_DATA (push, mask[2]);
428   PUSH_DATA (push, mask[3]);
429}
430
431static void
432nv50_validate_min_samples(struct nv50_context *nv50)
433{
434   struct nouveau_pushbuf *push = nv50->base.pushbuf;
435   int samples;
436
437   if (nv50->screen->tesla->oclass < NVA3_3D_CLASS)
438      return;
439
440   samples = util_next_power_of_two(nv50->min_samples);
441   if (samples > 1)
442      samples |= NVA3_3D_SAMPLE_SHADING_ENABLE;
443
444   BEGIN_NV04(push, SUBC_3D(NVA3_3D_SAMPLE_SHADING), 1);
445   PUSH_DATA (push, samples);
446}
447
448static void
449nv50_switch_pipe_context(struct nv50_context *ctx_to)
450{
451   struct nv50_context *ctx_from = ctx_to->screen->cur_ctx;
452
453   if (ctx_from)
454      ctx_to->state = ctx_from->state;
455   else
456      ctx_to->state = ctx_to->screen->save_state;
457
458   ctx_to->dirty_3d = ~0;
459   ctx_to->dirty_cp = ~0;
460   ctx_to->viewports_dirty = ~0;
461   ctx_to->scissors_dirty = ~0;
462
463   ctx_to->constbuf_dirty[NV50_SHADER_STAGE_VERTEX] =
464   ctx_to->constbuf_dirty[NV50_SHADER_STAGE_GEOMETRY] =
465   ctx_to->constbuf_dirty[NV50_SHADER_STAGE_FRAGMENT] = (1 << NV50_MAX_PIPE_CONSTBUFS) - 1;
466
467   if (!ctx_to->vertex)
468      ctx_to->dirty_3d &= ~(NV50_NEW_3D_VERTEX | NV50_NEW_3D_ARRAYS);
469
470   if (!ctx_to->vertprog)
471      ctx_to->dirty_3d &= ~NV50_NEW_3D_VERTPROG;
472   if (!ctx_to->fragprog)
473      ctx_to->dirty_3d &= ~NV50_NEW_3D_FRAGPROG;
474
475   if (!ctx_to->blend)
476      ctx_to->dirty_3d &= ~NV50_NEW_3D_BLEND;
477   if (!ctx_to->rast)
478#ifdef NV50_SCISSORS_CLIPPING
479      ctx_to->dirty_3d &= ~(NV50_NEW_3D_RASTERIZER | NV50_NEW_3D_SCISSOR);
480#else
481      ctx_to->dirty_3d &= ~NV50_NEW_3D_RASTERIZER;
482#endif
483   if (!ctx_to->zsa)
484      ctx_to->dirty_3d &= ~NV50_NEW_3D_ZSA;
485
486   ctx_to->screen->cur_ctx = ctx_to;
487}
488
489static struct nv50_state_validate
490validate_list_3d[] = {
491    { nv50_validate_fb,            NV50_NEW_3D_FRAMEBUFFER },
492    { nv50_validate_blend,         NV50_NEW_3D_BLEND },
493    { nv50_validate_zsa,           NV50_NEW_3D_ZSA },
494    { nv50_validate_sample_mask,   NV50_NEW_3D_SAMPLE_MASK },
495    { nv50_validate_rasterizer,    NV50_NEW_3D_RASTERIZER },
496    { nv50_validate_blend_colour,  NV50_NEW_3D_BLEND_COLOUR },
497    { nv50_validate_stencil_ref,   NV50_NEW_3D_STENCIL_REF },
498    { nv50_validate_stipple,       NV50_NEW_3D_STIPPLE },
499#ifdef NV50_SCISSORS_CLIPPING
500    { nv50_validate_scissor,       NV50_NEW_3D_SCISSOR | NV50_NEW_3D_VIEWPORT |
501                                   NV50_NEW_3D_RASTERIZER |
502                                   NV50_NEW_3D_FRAMEBUFFER },
503#else
504    { nv50_validate_scissor,       NV50_NEW_3D_SCISSOR },
505#endif
506    { nv50_validate_viewport,      NV50_NEW_3D_VIEWPORT },
507    { nv50_validate_window_rects,  NV50_NEW_3D_WINDOW_RECTS },
508    { nv50_vertprog_validate,      NV50_NEW_3D_VERTPROG },
509    { nv50_gmtyprog_validate,      NV50_NEW_3D_GMTYPROG },
510    { nv50_fragprog_validate,      NV50_NEW_3D_FRAGPROG | NV50_NEW_3D_RASTERIZER |
511                                   NV50_NEW_3D_MIN_SAMPLES | NV50_NEW_3D_ZSA |
512                                   NV50_NEW_3D_FRAMEBUFFER},
513    { nv50_fp_linkage_validate,    NV50_NEW_3D_FRAGPROG | NV50_NEW_3D_VERTPROG |
514                                   NV50_NEW_3D_GMTYPROG | NV50_NEW_3D_RASTERIZER },
515    { nv50_gp_linkage_validate,    NV50_NEW_3D_GMTYPROG | NV50_NEW_3D_VERTPROG },
516    { nv50_validate_derived_rs,    NV50_NEW_3D_FRAGPROG | NV50_NEW_3D_RASTERIZER |
517                                   NV50_NEW_3D_VERTPROG | NV50_NEW_3D_GMTYPROG },
518    { nv50_validate_derived_2,     NV50_NEW_3D_ZSA | NV50_NEW_3D_FRAMEBUFFER },
519    { nv50_validate_clip,          NV50_NEW_3D_CLIP | NV50_NEW_3D_RASTERIZER |
520                                   NV50_NEW_3D_VERTPROG | NV50_NEW_3D_GMTYPROG },
521    { nv50_constbufs_validate,     NV50_NEW_3D_CONSTBUF },
522    { nv50_validate_textures,      NV50_NEW_3D_TEXTURES },
523    { nv50_validate_samplers,      NV50_NEW_3D_SAMPLERS },
524    { nv50_stream_output_validate, NV50_NEW_3D_STRMOUT |
525                                   NV50_NEW_3D_VERTPROG | NV50_NEW_3D_GMTYPROG },
526    { nv50_vertex_arrays_validate, NV50_NEW_3D_VERTEX | NV50_NEW_3D_ARRAYS },
527    { nv50_validate_min_samples,   NV50_NEW_3D_MIN_SAMPLES },
528};
529
530bool
531nv50_state_validate(struct nv50_context *nv50, uint32_t mask,
532                    struct nv50_state_validate *validate_list, int size,
533                    uint32_t *dirty, struct nouveau_bufctx *bufctx)
534{
535   uint32_t state_mask;
536   int ret;
537   unsigned i;
538
539   if (nv50->screen->cur_ctx != nv50)
540      nv50_switch_pipe_context(nv50);
541
542   state_mask = *dirty & mask;
543
544   if (state_mask) {
545      for (i = 0; i < size; i++) {
546         struct nv50_state_validate *validate = &validate_list[i];
547
548         if (state_mask & validate->states)
549            validate->func(nv50);
550      }
551      *dirty &= ~state_mask;
552
553      if (nv50->state.rt_serialize) {
554         nv50->state.rt_serialize = false;
555         BEGIN_NV04(nv50->base.pushbuf, SUBC_3D(NV50_GRAPH_SERIALIZE), 1);
556         PUSH_DATA (nv50->base.pushbuf, 0);
557      }
558
559      nv50_bufctx_fence(bufctx, false);
560   }
561   nouveau_pushbuf_bufctx(nv50->base.pushbuf, bufctx);
562   ret = nouveau_pushbuf_validate(nv50->base.pushbuf);
563
564   return !ret;
565}
566
567bool
568nv50_state_validate_3d(struct nv50_context *nv50, uint32_t mask)
569{
570   bool ret;
571
572   ret = nv50_state_validate(nv50, mask, validate_list_3d,
573                             ARRAY_SIZE(validate_list_3d), &nv50->dirty_3d,
574                             nv50->bufctx_3d);
575
576   if (unlikely(nv50->state.flushed)) {
577      nv50->state.flushed = false;
578      nv50_bufctx_fence(nv50->bufctx_3d, true);
579   }
580   return ret;
581}
582