• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #include "util/u_viewport.h"
3 
4 #include "nv50/nv50_context.h"
5 
6 static inline void
nv50_fb_set_null_rt(struct nouveau_pushbuf * push,unsigned i)7 nv50_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 
19 static void
nv50_validate_fb(struct nv50_context * nv50)20 nv50_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 
149 static void
nv50_validate_blend_colour(struct nv50_context * nv50)150 nv50_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 
161 static void
nv50_validate_stencil_ref(struct nv50_context * nv50)162 nv50_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 
172 static void
nv50_validate_stipple(struct nv50_context * nv50)173 nv50_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 
183 static void
nv50_validate_scissor(struct nv50_context * nv50)184 nv50_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 
247 static void
nv50_validate_viewport(struct nv50_context * nv50)248 nv50_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 
286 static void
nv50_validate_window_rects(struct nv50_context * nv50)287 nv50_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 
312 static inline void
nv50_check_program_ucps(struct nv50_context * nv50,struct nv50_program * vp,uint8_t mask)313 nv50_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  */
337 static void
nv50_validate_derived_2(struct nv50_context * nv50)338 nv50_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 
350 static void
nv50_validate_clip(struct nv50_context * nv50)351 nv50_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) | 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 
384 static void
nv50_validate_blend(struct nv50_context * nv50)385 nv50_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 
393 static void
nv50_validate_zsa(struct nv50_context * nv50)394 nv50_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 
402 static void
nv50_validate_rasterizer(struct nv50_context * nv50)403 nv50_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 
411 static void
nv50_validate_sample_mask(struct nv50_context * nv50)412 nv50_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 
431 static void
nv50_validate_min_samples(struct nv50_context * nv50)432 nv50_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 
448 static void
nv50_switch_pipe_context(struct nv50_context * ctx_to)449 nv50_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[0] =
464    ctx_to->constbuf_dirty[1] =
465    ctx_to->constbuf_dirty[2] = (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 
489 static struct nv50_state_validate
490 validate_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 
530 bool
nv50_state_validate(struct nv50_context * nv50,uint32_t mask,struct nv50_state_validate * validate_list,int size,uint32_t * dirty,struct nouveau_bufctx * bufctx)531 nv50_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 
567 bool
nv50_state_validate_3d(struct nv50_context * nv50,uint32_t mask)568 nv50_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