1
2#include "nv50_context.h"
3#include "os/os_time.h"
4
5static void
6nv50_validate_fb(struct nv50_context *nv50)
7{
8   struct nouveau_pushbuf *push = nv50->base.pushbuf;
9   struct pipe_framebuffer_state *fb = &nv50->framebuffer;
10   unsigned i;
11   unsigned ms_mode = NV50_3D_MULTISAMPLE_MODE_MS1;
12
13   nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_FB);
14
15   BEGIN_NV04(push, NV50_3D(RT_CONTROL), 1);
16   PUSH_DATA (push, (076543210 << 4) | fb->nr_cbufs);
17   BEGIN_NV04(push, NV50_3D(SCREEN_SCISSOR_HORIZ), 2);
18   PUSH_DATA (push, fb->width << 16);
19   PUSH_DATA (push, fb->height << 16);
20
21   for (i = 0; i < fb->nr_cbufs; ++i) {
22      struct nv50_miptree *mt = nv50_miptree(fb->cbufs[i]->texture);
23      struct nv50_surface *sf = nv50_surface(fb->cbufs[i]);
24      struct nouveau_bo *bo = mt->base.bo;
25
26      BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(i)), 5);
27      PUSH_DATAh(push, bo->offset + sf->offset);
28      PUSH_DATA (push, bo->offset + sf->offset);
29      PUSH_DATA (push, nv50_format_table[sf->base.format].rt);
30      if (likely(nouveau_bo_memtype(bo))) {
31         PUSH_DATA (push, mt->level[sf->base.u.tex.level].tile_mode);
32         PUSH_DATA (push, mt->layer_stride >> 2);
33         BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2);
34         PUSH_DATA (push, sf->width);
35         PUSH_DATA (push, sf->height);
36         BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1);
37         PUSH_DATA (push, sf->depth);
38      } else {
39         PUSH_DATA (push, 0);
40         PUSH_DATA (push, 0);
41         BEGIN_NV04(push, NV50_3D(RT_HORIZ(i)), 2);
42         PUSH_DATA (push, NV50_3D_RT_HORIZ_LINEAR | mt->level[0].pitch);
43         PUSH_DATA (push, sf->height);
44         BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1);
45         PUSH_DATA (push, 0);
46
47         assert(!fb->zsbuf);
48         assert(!mt->ms_mode);
49      }
50
51      ms_mode = mt->ms_mode;
52
53      if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
54         nv50->state.rt_serialize = TRUE;
55      mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
56      mt->base.status &= NOUVEAU_BUFFER_STATUS_GPU_READING;
57
58      /* only register for writing, otherwise we'd always serialize here */
59      BCTX_REFN(nv50->bufctx_3d, FB, &mt->base, WR);
60   }
61
62   if (fb->zsbuf) {
63      struct nv50_miptree *mt = nv50_miptree(fb->zsbuf->texture);
64      struct nv50_surface *sf = nv50_surface(fb->zsbuf);
65      struct nouveau_bo *bo = mt->base.bo;
66      int unk = mt->base.base.target == PIPE_TEXTURE_2D;
67
68      BEGIN_NV04(push, NV50_3D(ZETA_ADDRESS_HIGH), 5);
69      PUSH_DATAh(push, bo->offset + sf->offset);
70      PUSH_DATA (push, bo->offset + sf->offset);
71      PUSH_DATA (push, nv50_format_table[fb->zsbuf->format].rt);
72      PUSH_DATA (push, mt->level[sf->base.u.tex.level].tile_mode);
73      PUSH_DATA (push, mt->layer_stride >> 2);
74      BEGIN_NV04(push, NV50_3D(ZETA_ENABLE), 1);
75      PUSH_DATA (push, 1);
76      BEGIN_NV04(push, NV50_3D(ZETA_HORIZ), 3);
77      PUSH_DATA (push, sf->width);
78      PUSH_DATA (push, sf->height);
79      PUSH_DATA (push, (unk << 16) | sf->depth);
80
81      ms_mode = mt->ms_mode;
82
83      if (mt->base.status & NOUVEAU_BUFFER_STATUS_GPU_READING)
84         nv50->state.rt_serialize = TRUE;
85      mt->base.status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING;
86      mt->base.status &= NOUVEAU_BUFFER_STATUS_GPU_READING;
87
88      BCTX_REFN(nv50->bufctx_3d, FB, &mt->base, WR);
89   } else {
90      BEGIN_NV04(push, NV50_3D(ZETA_ENABLE), 1);
91      PUSH_DATA (push, 0);
92   }
93
94   BEGIN_NV04(push, NV50_3D(MULTISAMPLE_MODE), 1);
95   PUSH_DATA (push, ms_mode);
96
97   BEGIN_NV04(push, NV50_3D(VIEWPORT_HORIZ(0)), 2);
98   PUSH_DATA (push, fb->width << 16);
99   PUSH_DATA (push, fb->height << 16);
100}
101
102static void
103nv50_validate_blend_colour(struct nv50_context *nv50)
104{
105   struct nouveau_pushbuf *push = nv50->base.pushbuf;
106
107   BEGIN_NV04(push, NV50_3D(BLEND_COLOR(0)), 4);
108   PUSH_DATAf(push, nv50->blend_colour.color[0]);
109   PUSH_DATAf(push, nv50->blend_colour.color[1]);
110   PUSH_DATAf(push, nv50->blend_colour.color[2]);
111   PUSH_DATAf(push, nv50->blend_colour.color[3]);
112}
113
114static void
115nv50_validate_stencil_ref(struct nv50_context *nv50)
116{
117   struct nouveau_pushbuf *push = nv50->base.pushbuf;
118
119   BEGIN_NV04(push, NV50_3D(STENCIL_FRONT_FUNC_REF), 1);
120   PUSH_DATA (push, nv50->stencil_ref.ref_value[0]);
121   BEGIN_NV04(push, NV50_3D(STENCIL_BACK_FUNC_REF), 1);
122   PUSH_DATA (push, nv50->stencil_ref.ref_value[1]);
123}
124
125static void
126nv50_validate_stipple(struct nv50_context *nv50)
127{
128   struct nouveau_pushbuf *push = nv50->base.pushbuf;
129   unsigned i;
130
131   BEGIN_NV04(push, NV50_3D(POLYGON_STIPPLE_PATTERN(0)), 32);
132   for (i = 0; i < 32; ++i)
133      PUSH_DATA(push, util_bswap32(nv50->stipple.stipple[i]));
134}
135
136static void
137nv50_validate_scissor(struct nv50_context *nv50)
138{
139   struct nouveau_pushbuf *push = nv50->base.pushbuf;
140   struct pipe_scissor_state *s = &nv50->scissor;
141#ifdef NV50_SCISSORS_CLIPPING
142   struct pipe_viewport_state *vp = &nv50->viewport;
143   int minx, maxx, miny, maxy;
144
145   if (!(nv50->dirty &
146         (NV50_NEW_SCISSOR | NV50_NEW_VIEWPORT | NV50_NEW_FRAMEBUFFER)) &&
147       nv50->state.scissor == nv50->rast->pipe.scissor)
148      return;
149   nv50->state.scissor = nv50->rast->pipe.scissor;
150
151   if (nv50->state.scissor) {
152      minx = s->minx;
153      maxx = s->maxx;
154      miny = s->miny;
155      maxy = s->maxy;
156   } else {
157      minx = 0;
158      maxx = nv50->framebuffer.width;
159      miny = 0;
160      maxy = nv50->framebuffer.height;
161   }
162
163   minx = MAX2(minx, (int)(vp->translate[0] - fabsf(vp->scale[0])));
164   maxx = MIN2(maxx, (int)(vp->translate[0] + fabsf(vp->scale[0])));
165   miny = MAX2(miny, (int)(vp->translate[1] - fabsf(vp->scale[1])));
166   maxy = MIN2(maxy, (int)(vp->translate[1] + fabsf(vp->scale[1])));
167
168   BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(0)), 2);
169   PUSH_DATA (push, (maxx << 16) | minx);
170   PUSH_DATA (push, (maxy << 16) | miny);
171#else
172   BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(0)), 2);
173   PUSH_DATA (push, (s->maxx << 16) | s->minx);
174   PUSH_DATA (push, (s->maxy << 16) | s->miny);
175#endif
176}
177
178static void
179nv50_validate_viewport(struct nv50_context *nv50)
180{
181   struct nouveau_pushbuf *push = nv50->base.pushbuf;
182   float zmin, zmax;
183
184   BEGIN_NV04(push, NV50_3D(VIEWPORT_TRANSLATE_X(0)), 3);
185   PUSH_DATAf(push, nv50->viewport.translate[0]);
186   PUSH_DATAf(push, nv50->viewport.translate[1]);
187   PUSH_DATAf(push, nv50->viewport.translate[2]);
188   BEGIN_NV04(push, NV50_3D(VIEWPORT_SCALE_X(0)), 3);
189   PUSH_DATAf(push, nv50->viewport.scale[0]);
190   PUSH_DATAf(push, nv50->viewport.scale[1]);
191   PUSH_DATAf(push, nv50->viewport.scale[2]);
192
193   zmin = nv50->viewport.translate[2] - fabsf(nv50->viewport.scale[2]);
194   zmax = nv50->viewport.translate[2] + fabsf(nv50->viewport.scale[2]);
195
196#ifdef NV50_SCISSORS_CLIPPING
197   BEGIN_NV04(push, NV50_3D(DEPTH_RANGE_NEAR(0)), 2);
198   PUSH_DATAf(push, zmin);
199   PUSH_DATAf(push, zmax);
200#endif
201}
202
203static INLINE void
204nv50_check_program_ucps(struct nv50_context *nv50,
205                        struct nv50_program *vp, uint8_t mask)
206{
207   const unsigned n = util_logbase2(mask) + 1;
208
209   if (vp->vp.clpd_nr >= n)
210      return;
211   nv50_program_destroy(nv50, vp);
212
213   vp->vp.clpd_nr = n;
214   if (likely(vp == nv50->vertprog)) {
215      nv50->dirty |= NV50_NEW_VERTPROG;
216      nv50_vertprog_validate(nv50);
217   } else {
218      nv50->dirty |= NV50_NEW_GMTYPROG;
219      nv50_gmtyprog_validate(nv50);
220   }
221   nv50_fp_linkage_validate(nv50);
222}
223
224static void
225nv50_validate_clip(struct nv50_context *nv50)
226{
227   struct nouveau_pushbuf *push = nv50->base.pushbuf;
228   struct nv50_program *vp;
229   uint8_t clip_enable;
230
231   if (nv50->dirty & NV50_NEW_CLIP) {
232      BEGIN_NV04(push, NV50_3D(CB_ADDR), 1);
233      PUSH_DATA (push, (0 << 8) | NV50_CB_AUX);
234      BEGIN_NI04(push, NV50_3D(CB_DATA(0)), PIPE_MAX_CLIP_PLANES * 4);
235      PUSH_DATAp(push, &nv50->clip.ucp[0][0], PIPE_MAX_CLIP_PLANES * 4);
236   }
237
238   vp = nv50->gmtyprog;
239   if (likely(!vp))
240      vp = nv50->vertprog;
241
242   clip_enable = nv50->rast->pipe.clip_plane_enable;
243
244   BEGIN_NV04(push, NV50_3D(CLIP_DISTANCE_ENABLE), 1);
245   PUSH_DATA (push, clip_enable);
246
247   if (clip_enable)
248      nv50_check_program_ucps(nv50, vp, clip_enable);
249}
250
251static void
252nv50_validate_blend(struct nv50_context *nv50)
253{
254   struct nouveau_pushbuf *push = nv50->base.pushbuf;
255
256   PUSH_SPACE(push, nv50->blend->size);
257   PUSH_DATAp(push, nv50->blend->state, nv50->blend->size);
258}
259
260static void
261nv50_validate_zsa(struct nv50_context *nv50)
262{
263   struct nouveau_pushbuf *push = nv50->base.pushbuf;
264
265   PUSH_SPACE(push, nv50->zsa->size);
266   PUSH_DATAp(push, nv50->zsa->state, nv50->zsa->size);
267}
268
269static void
270nv50_validate_rasterizer(struct nv50_context *nv50)
271{
272   struct nouveau_pushbuf *push = nv50->base.pushbuf;
273
274   PUSH_SPACE(push, nv50->rast->size);
275   PUSH_DATAp(push, nv50->rast->state, nv50->rast->size);
276}
277
278static void
279nv50_validate_sample_mask(struct nv50_context *nv50)
280{
281   struct nouveau_pushbuf *push = nv50->base.pushbuf;
282
283   unsigned mask[4] =
284   {
285      nv50->sample_mask & 0xffff,
286      nv50->sample_mask & 0xffff,
287      nv50->sample_mask & 0xffff,
288      nv50->sample_mask & 0xffff
289   };
290
291   BEGIN_NV04(push, NV50_3D(MSAA_MASK(0)), 4);
292   PUSH_DATA (push, mask[0]);
293   PUSH_DATA (push, mask[1]);
294   PUSH_DATA (push, mask[2]);
295   PUSH_DATA (push, mask[3]);
296}
297
298static void
299nv50_switch_pipe_context(struct nv50_context *ctx_to)
300{
301   struct nv50_context *ctx_from = ctx_to->screen->cur_ctx;
302
303   if (ctx_from)
304      ctx_to->state = ctx_from->state;
305
306   ctx_to->dirty = ~0;
307
308   if (!ctx_to->vertex)
309      ctx_to->dirty &= ~(NV50_NEW_VERTEX | NV50_NEW_ARRAYS);
310
311   if (!ctx_to->vertprog)
312      ctx_to->dirty &= ~NV50_NEW_VERTPROG;
313   if (!ctx_to->fragprog)
314      ctx_to->dirty &= ~NV50_NEW_FRAGPROG;
315
316   if (!ctx_to->blend)
317      ctx_to->dirty &= ~NV50_NEW_BLEND;
318   if (!ctx_to->rast)
319#ifdef NV50_SCISSORS_CLIPPING
320      ctx_to->dirty &= ~(NV50_NEW_RASTERIZER | NV50_NEW_SCISSOR);
321#else
322      ctx_to->dirty &= ~NV50_NEW_RASTERIZER;
323#endif
324   if (!ctx_to->zsa)
325      ctx_to->dirty &= ~NV50_NEW_ZSA;
326
327   ctx_to->screen->cur_ctx = ctx_to;
328}
329
330static struct state_validate {
331    void (*func)(struct nv50_context *);
332    uint32_t states;
333} validate_list[] = {
334    { nv50_validate_fb,            NV50_NEW_FRAMEBUFFER },
335    { nv50_validate_blend,         NV50_NEW_BLEND },
336    { nv50_validate_zsa,           NV50_NEW_ZSA },
337    { nv50_validate_sample_mask,   NV50_NEW_SAMPLE_MASK },
338    { nv50_validate_rasterizer,    NV50_NEW_RASTERIZER },
339    { nv50_validate_blend_colour,  NV50_NEW_BLEND_COLOUR },
340    { nv50_validate_stencil_ref,   NV50_NEW_STENCIL_REF },
341    { nv50_validate_stipple,       NV50_NEW_STIPPLE },
342#ifdef NV50_SCISSORS_CLIPPING
343    { nv50_validate_scissor,       NV50_NEW_SCISSOR | NV50_NEW_VIEWPORT |
344                                   NV50_NEW_RASTERIZER |
345                                   NV50_NEW_FRAMEBUFFER },
346#else
347    { nv50_validate_scissor,       NV50_NEW_SCISSOR },
348#endif
349    { nv50_validate_viewport,      NV50_NEW_VIEWPORT },
350    { nv50_vertprog_validate,      NV50_NEW_VERTPROG },
351    { nv50_gmtyprog_validate,      NV50_NEW_GMTYPROG },
352    { nv50_fragprog_validate,      NV50_NEW_FRAGPROG },
353    { nv50_fp_linkage_validate,    NV50_NEW_FRAGPROG | NV50_NEW_VERTPROG |
354                                   NV50_NEW_GMTYPROG | NV50_NEW_RASTERIZER },
355    { nv50_gp_linkage_validate,    NV50_NEW_GMTYPROG | NV50_NEW_VERTPROG },
356    { nv50_validate_derived_rs,    NV50_NEW_FRAGPROG | NV50_NEW_RASTERIZER |
357                                   NV50_NEW_VERTPROG | NV50_NEW_GMTYPROG },
358    { nv50_validate_clip,          NV50_NEW_CLIP | NV50_NEW_RASTERIZER |
359                                   NV50_NEW_VERTPROG | NV50_NEW_GMTYPROG },
360    { nv50_constbufs_validate,     NV50_NEW_CONSTBUF },
361    { nv50_validate_textures,      NV50_NEW_TEXTURES },
362    { nv50_validate_samplers,      NV50_NEW_SAMPLERS },
363    { nv50_stream_output_validate, NV50_NEW_STRMOUT |
364                                   NV50_NEW_VERTPROG | NV50_NEW_GMTYPROG },
365    { nv50_vertex_arrays_validate, NV50_NEW_VERTEX | NV50_NEW_ARRAYS }
366};
367#define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0]))
368
369boolean
370nv50_state_validate(struct nv50_context *nv50, uint32_t mask, unsigned words)
371{
372   uint32_t state_mask;
373   int ret;
374   unsigned i;
375
376   if (nv50->screen->cur_ctx != nv50)
377      nv50_switch_pipe_context(nv50);
378
379   state_mask = nv50->dirty & mask;
380
381   if (state_mask) {
382      for (i = 0; i < validate_list_len; ++i) {
383         struct state_validate *validate = &validate_list[i];
384
385         if (state_mask & validate->states)
386            validate->func(nv50);
387      }
388      nv50->dirty &= ~state_mask;
389
390      if (nv50->state.rt_serialize) {
391         nv50->state.rt_serialize = FALSE;
392         BEGIN_NV04(nv50->base.pushbuf, SUBC_3D(NV50_GRAPH_SERIALIZE), 1);
393         PUSH_DATA (nv50->base.pushbuf, 0);
394      }
395
396      nv50_bufctx_fence(nv50->bufctx_3d, FALSE);
397   }
398   nouveau_pushbuf_bufctx(nv50->base.pushbuf, nv50->bufctx_3d);
399   ret = nouveau_pushbuf_validate(nv50->base.pushbuf);
400
401   if (unlikely(nv50->state.flushed)) {
402      nv50->state.flushed = FALSE;
403      nv50_bufctx_fence(nv50->bufctx_3d, TRUE);
404   }
405   return !ret;
406}
407