Merge branch 'draw-instanced'
[mesa.git] / src / gallium / drivers / nvc0 / nvc0_state_validate.c
1
2 #include "nvc0_context.h"
3 #include "os/os_time.h"
4
5 static void
6 nvc0_validate_zcull(struct nvc0_context *nvc0)
7 {
8 struct nouveau_channel *chan = nvc0->screen->base.channel;
9 struct pipe_framebuffer_state *fb = &nvc0->framebuffer;
10 struct nvc0_surface *sf = nvc0_surface(fb->zsbuf);
11 struct nvc0_miptree *mt = nvc0_miptree(sf->base.texture);
12 struct nouveau_bo *bo = mt->base.bo;
13 uint32_t size;
14 uint32_t offset = align(mt->total_size, 1 << 17);
15 unsigned width, height;
16
17 assert(mt->base.base.depth0 == 1 && mt->base.base.array_size < 2);
18
19 size = mt->total_size * 2;
20
21 height = align(fb->height, 32);
22 width = fb->width % 224;
23 if (width)
24 width = fb->width + (224 - width);
25 else
26 width = fb->width;
27
28 BEGIN_RING(chan, RING_3D_(0x1590), 1); /* ZCULL_REGION_INDEX (bits 0x3f) */
29 OUT_RING (chan, 0);
30 BEGIN_RING(chan, RING_3D_(0x07e8), 2); /* ZCULL_ADDRESS_A_HIGH */
31 OUT_RELOCh(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
32 OUT_RELOCl(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
33 offset += 1 << 17;
34 BEGIN_RING(chan, RING_3D_(0x07f0), 2); /* ZCULL_ADDRESS_B_HIGH */
35 OUT_RELOCh(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
36 OUT_RELOCl(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
37 BEGIN_RING(chan, RING_3D_(0x07e0), 2);
38 OUT_RING (chan, size);
39 OUT_RING (chan, size >> 16);
40 BEGIN_RING(chan, RING_3D_(0x15c8), 1); /* bits 0x3 */
41 OUT_RING (chan, 2);
42 BEGIN_RING(chan, RING_3D_(0x07c0), 4); /* ZCULL dimensions */
43 OUT_RING (chan, width);
44 OUT_RING (chan, height);
45 OUT_RING (chan, 1);
46 OUT_RING (chan, 0);
47 BEGIN_RING(chan, RING_3D_(0x15fc), 2);
48 OUT_RING (chan, 0); /* bits 0xffff */
49 OUT_RING (chan, 0); /* bits 0xffff */
50 BEGIN_RING(chan, RING_3D_(0x1958), 1);
51 OUT_RING (chan, 0); /* bits ~0 */
52 }
53
54 static void
55 nvc0_validate_fb(struct nvc0_context *nvc0)
56 {
57 struct nouveau_channel *chan = nvc0->screen->base.channel;
58 struct pipe_framebuffer_state *fb = &nvc0->framebuffer;
59 unsigned i;
60
61 nvc0_bufctx_reset(nvc0, NVC0_BUFCTX_FRAME);
62
63 BEGIN_RING(chan, RING_3D(RT_CONTROL), 1);
64 OUT_RING (chan, (076543210 << 4) | fb->nr_cbufs);
65 BEGIN_RING(chan, RING_3D(SCREEN_SCISSOR_HORIZ), 2);
66 OUT_RING (chan, fb->width << 16);
67 OUT_RING (chan, fb->height << 16);
68
69 for (i = 0; i < fb->nr_cbufs; ++i) {
70 struct nvc0_miptree *mt = nvc0_miptree(fb->cbufs[i]->texture);
71 struct nvc0_surface *sf = nvc0_surface(fb->cbufs[i]);
72 struct nouveau_bo *bo = mt->base.bo;
73 uint32_t offset = sf->offset;
74
75 BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(i)), 8);
76 OUT_RELOCh(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
77 OUT_RELOCl(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
78 OUT_RING (chan, sf->width);
79 OUT_RING (chan, sf->height);
80 OUT_RING (chan, nvc0_format_table[sf->base.format].rt);
81 OUT_RING (chan, (mt->layout_3d << 16) |
82 mt->level[sf->base.u.tex.level].tile_mode);
83 OUT_RING (chan, sf->depth);
84 OUT_RING (chan, mt->layer_stride >> 2);
85
86 nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_FRAME, &mt->base,
87 NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
88 }
89
90 if (fb->zsbuf) {
91 struct nvc0_miptree *mt = nvc0_miptree(fb->zsbuf->texture);
92 struct nvc0_surface *sf = nvc0_surface(fb->zsbuf);
93 struct nouveau_bo *bo = mt->base.bo;
94 int unk = mt->base.base.target == PIPE_TEXTURE_2D;
95 uint32_t offset = sf->offset;
96
97 BEGIN_RING(chan, RING_3D(ZETA_ADDRESS_HIGH), 5);
98 OUT_RELOCh(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
99 OUT_RELOCl(chan, bo, offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
100 OUT_RING (chan, nvc0_format_table[fb->zsbuf->format].rt);
101 OUT_RING (chan, mt->level[sf->base.u.tex.level].tile_mode);
102 OUT_RING (chan, mt->layer_stride >> 2);
103 BEGIN_RING(chan, RING_3D(ZETA_ENABLE), 1);
104 OUT_RING (chan, 1);
105 BEGIN_RING(chan, RING_3D(ZETA_HORIZ), 3);
106 OUT_RING (chan, sf->width);
107 OUT_RING (chan, sf->height);
108 OUT_RING (chan, (unk << 16) | sf->depth);
109
110 nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_FRAME, &mt->base,
111 NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
112 } else {
113 BEGIN_RING(chan, RING_3D(ZETA_ENABLE), 1);
114 OUT_RING (chan, 0);
115 }
116
117 #ifndef NVC0_SCISSORS_CLIPPING
118 BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2);
119 OUT_RING (chan, fb->width << 16);
120 OUT_RING (chan, fb->height << 16);
121 #endif
122 }
123
124 static void
125 nvc0_validate_blend_colour(struct nvc0_context *nvc0)
126 {
127 struct nouveau_channel *chan = nvc0->screen->base.channel;
128
129 BEGIN_RING(chan, RING_3D(BLEND_COLOR(0)), 4);
130 OUT_RINGf (chan, nvc0->blend_colour.color[0]);
131 OUT_RINGf (chan, nvc0->blend_colour.color[1]);
132 OUT_RINGf (chan, nvc0->blend_colour.color[2]);
133 OUT_RINGf (chan, nvc0->blend_colour.color[3]);
134 }
135
136 static void
137 nvc0_validate_stencil_ref(struct nvc0_context *nvc0)
138 {
139 struct nouveau_channel *chan = nvc0->screen->base.channel;
140
141 BEGIN_RING(chan, RING_3D(STENCIL_FRONT_FUNC_REF), 1);
142 OUT_RING (chan, nvc0->stencil_ref.ref_value[0]);
143 BEGIN_RING(chan, RING_3D(STENCIL_BACK_FUNC_REF), 1);
144 OUT_RING (chan, nvc0->stencil_ref.ref_value[1]);
145 }
146
147 static void
148 nvc0_validate_stipple(struct nvc0_context *nvc0)
149 {
150 struct nouveau_channel *chan = nvc0->screen->base.channel;
151 unsigned i;
152
153 BEGIN_RING(chan, RING_3D(POLYGON_STIPPLE_PATTERN(0)), 32);
154 for (i = 0; i < 32; ++i)
155 OUT_RING(chan, util_bswap32(nvc0->stipple.stipple[i]));
156 }
157
158 static void
159 nvc0_validate_scissor(struct nvc0_context *nvc0)
160 {
161 struct nouveau_channel *chan = nvc0->screen->base.channel;
162 struct pipe_scissor_state *s = &nvc0->scissor;
163 #ifdef NVC0_SCISSORS_CLIPPING
164 struct pipe_viewport_state *vp = &nvc0->viewport;
165 int minx, maxx, miny, maxy;
166
167 if (!(nvc0->dirty &
168 (NVC0_NEW_SCISSOR | NVC0_NEW_VIEWPORT | NVC0_NEW_FRAMEBUFFER)) &&
169 nvc0->state.scissor == nvc0->rast->pipe.scissor)
170 return;
171 nvc0->state.scissor = nvc0->rast->pipe.scissor;
172
173 if (nvc0->state.scissor) {
174 minx = s->minx;
175 maxx = s->maxx;
176 miny = s->miny;
177 maxy = s->maxy;
178 } else {
179 minx = 0;
180 maxx = nvc0->framebuffer.width;
181 miny = 0;
182 maxy = nvc0->framebuffer.height;
183 }
184
185 minx = MAX2(minx, (int)(vp->translate[0] - fabsf(vp->scale[0])));
186 maxx = MIN2(maxx, (int)(vp->translate[0] + fabsf(vp->scale[0])));
187 miny = MAX2(miny, (int)(vp->translate[1] - fabsf(vp->scale[1])));
188 maxy = MIN2(maxy, (int)(vp->translate[1] + fabsf(vp->scale[1])));
189
190 BEGIN_RING(chan, RING_3D(SCISSOR_HORIZ(0)), 2);
191 OUT_RING (chan, (maxx << 16) | minx);
192 OUT_RING (chan, (maxy << 16) | miny);
193 BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2);
194 OUT_RING (chan, ((maxx - minx) << 16) | minx);
195 OUT_RING (chan, ((maxy - miny) << 16) | miny);
196 #else
197 BEGIN_RING(chan, RING_3D(SCISSOR_HORIZ(0)), 2);
198 OUT_RING (chan, (s->maxx << 16) | s->minx);
199 OUT_RING (chan, (s->maxy << 16) | s->miny);
200 #endif
201 }
202
203 static void
204 nvc0_validate_viewport(struct nvc0_context *nvc0)
205 {
206 struct nouveau_channel *chan = nvc0->screen->base.channel;
207
208 BEGIN_RING(chan, RING_3D(VIEWPORT_TRANSLATE_X(0)), 3);
209 OUT_RINGf (chan, nvc0->viewport.translate[0]);
210 OUT_RINGf (chan, nvc0->viewport.translate[1]);
211 OUT_RINGf (chan, nvc0->viewport.translate[2]);
212 BEGIN_RING(chan, RING_3D(VIEWPORT_SCALE_X(0)), 3);
213 OUT_RINGf (chan, nvc0->viewport.scale[0]);
214 OUT_RINGf (chan, nvc0->viewport.scale[1]);
215 OUT_RINGf (chan, nvc0->viewport.scale[2]);
216
217 #ifdef NVC0_SCISSORS_CLIPPING
218 BEGIN_RING(chan, RING_3D(DEPTH_RANGE_NEAR(0)), 2);
219 OUT_RINGf (chan, nvc0->viewport.translate[2] - nvc0->viewport.scale[2]);
220 OUT_RINGf (chan, nvc0->viewport.translate[2] + nvc0->viewport.scale[2]);
221 #endif
222 }
223
224 static void
225 nvc0_validate_clip(struct nvc0_context *nvc0)
226 {
227 struct nouveau_channel *chan = nvc0->screen->base.channel;
228 uint32_t clip;
229
230 clip = nvc0->clip.depth_clamp ? 0x201a : 0x0002;
231 #ifndef NVC0_SCISSORS_CLIPPING
232 clip |= 0x1080;
233 #endif
234
235 BEGIN_RING(chan, RING_3D(VIEW_VOLUME_CLIP_CTRL), 1);
236 OUT_RING (chan, clip);
237
238 if (nvc0->clip.nr) {
239 struct nouveau_bo *bo = nvc0->screen->uniforms;
240
241 BEGIN_RING(chan, RING_3D(CB_SIZE), 3);
242 OUT_RING (chan, 256);
243 OUT_RELOCh(chan, bo, 5 << 16, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
244 OUT_RELOCl(chan, bo, 5 << 16, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
245 BEGIN_RING_1I(chan, RING_3D(CB_POS), nvc0->clip.nr * 4 + 1);
246 OUT_RING (chan, 0);
247 OUT_RINGp (chan, &nvc0->clip.ucp[0][0], nvc0->clip.nr * 4);
248
249 BEGIN_RING(chan, RING_3D(VP_CLIP_DISTANCE_ENABLE), 1);
250 OUT_RING (chan, (1 << nvc0->clip.nr) - 1);
251 } else {
252 IMMED_RING(chan, RING_3D(VP_CLIP_DISTANCE_ENABLE), 0);
253 }
254 }
255
256 static void
257 nvc0_validate_blend(struct nvc0_context *nvc0)
258 {
259 struct nouveau_channel *chan = nvc0->screen->base.channel;
260
261 WAIT_RING(chan, nvc0->blend->size);
262 OUT_RINGp(chan, nvc0->blend->state, nvc0->blend->size);
263 }
264
265 static void
266 nvc0_validate_zsa(struct nvc0_context *nvc0)
267 {
268 struct nouveau_channel *chan = nvc0->screen->base.channel;
269
270 WAIT_RING(chan, nvc0->zsa->size);
271 OUT_RINGp(chan, nvc0->zsa->state, nvc0->zsa->size);
272 }
273
274 static void
275 nvc0_validate_rasterizer(struct nvc0_context *nvc0)
276 {
277 struct nouveau_channel *chan = nvc0->screen->base.channel;
278
279 WAIT_RING(chan, nvc0->rast->size);
280 OUT_RINGp(chan, nvc0->rast->state, nvc0->rast->size);
281 }
282
283 static void
284 nvc0_constbufs_validate(struct nvc0_context *nvc0)
285 {
286 struct nouveau_channel *chan = nvc0->screen->base.channel;
287 struct nouveau_bo *bo;
288 unsigned s;
289
290 for (s = 0; s < 5; ++s) {
291 struct nvc0_resource *res;
292 int i;
293
294 while (nvc0->constbuf_dirty[s]) {
295 unsigned base = 0;
296 unsigned offset = 0, words = 0;
297 boolean rebind = TRUE;
298
299 i = ffs(nvc0->constbuf_dirty[s]) - 1;
300 nvc0->constbuf_dirty[s] &= ~(1 << i);
301
302 res = nvc0_resource(nvc0->constbuf[s][i]);
303 if (!res) {
304 BEGIN_RING(chan, RING_3D(CB_BIND(s)), 1);
305 OUT_RING (chan, (i << 4) | 0);
306 if (i == 0)
307 nvc0->state.uniform_buffer_bound[s] = 0;
308 continue;
309 }
310
311 if (!nvc0_resource_mapped_by_gpu(&res->base)) {
312 if (i == 0) {
313 base = s << 16;
314 bo = nvc0->screen->uniforms;
315
316 if (nvc0->state.uniform_buffer_bound[s] >= res->base.width0)
317 rebind = FALSE;
318 else
319 nvc0->state.uniform_buffer_bound[s] =
320 align(res->base.width0, 0x100);
321 } else {
322 bo = res->bo;
323 }
324 #if 0
325 nvc0_m2mf_push_linear(nvc0, bo, NOUVEAU_BO_VRAM,
326 base, res->base.width0, res->data);
327 BEGIN_RING(chan, RING_3D_(0x021c), 1);
328 OUT_RING (chan, 0x1111);
329 #else
330 words = res->base.width0 / 4;
331 #endif
332 } else {
333 bo = res->bo;
334 if (i == 0)
335 nvc0->state.uniform_buffer_bound[s] = 0;
336 }
337
338 if (bo != nvc0->screen->uniforms)
339 nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_CONSTANT, res,
340 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
341
342 if (rebind) {
343 BEGIN_RING(chan, RING_3D(CB_SIZE), 3);
344 OUT_RING (chan, align(res->base.width0, 0x100));
345 OUT_RELOCh(chan, bo, base, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
346 OUT_RELOCl(chan, bo, base, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
347 BEGIN_RING(chan, RING_3D(CB_BIND(s)), 1);
348 OUT_RING (chan, (i << 4) | 1);
349 }
350
351 while (words) {
352 unsigned nr = AVAIL_RING(chan);
353
354 if (nr < 16) {
355 FIRE_RING(chan);
356 continue;
357 }
358 nr = MIN2(MIN2(nr - 6, words), NV04_PFIFO_MAX_PACKET_LEN - 1);
359
360 BEGIN_RING(chan, RING_3D(CB_SIZE), 3);
361 OUT_RING (chan, align(res->base.width0, 0x100));
362 OUT_RELOCh(chan, bo, base, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
363 OUT_RELOCl(chan, bo, base, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
364 BEGIN_RING_1I(chan, RING_3D(CB_POS), nr + 1);
365 OUT_RING (chan, offset);
366 OUT_RINGp (chan, &res->data[offset], nr);
367
368 offset += nr * 4;
369 words -= nr;
370 }
371 }
372 }
373 }
374
375 static struct state_validate {
376 void (*func)(struct nvc0_context *);
377 uint32_t states;
378 } validate_list[] = {
379 { nvc0_validate_fb, NVC0_NEW_FRAMEBUFFER },
380 { nvc0_validate_blend, NVC0_NEW_BLEND },
381 { nvc0_validate_zsa, NVC0_NEW_ZSA },
382 { nvc0_validate_rasterizer, NVC0_NEW_RASTERIZER },
383 { nvc0_validate_blend_colour, NVC0_NEW_BLEND_COLOUR },
384 { nvc0_validate_stencil_ref, NVC0_NEW_STENCIL_REF },
385 { nvc0_validate_stipple, NVC0_NEW_STIPPLE },
386 #ifdef NVC0_SCISSORS_CLIPPING
387 { nvc0_validate_scissor, NVC0_NEW_SCISSOR | NVC0_NEW_VIEWPORT |
388 NVC0_NEW_RASTERIZER |
389 NVC0_NEW_FRAMEBUFFER },
390 #else
391 { nvc0_validate_scissor, NVC0_NEW_SCISSOR },
392 #endif
393 { nvc0_validate_viewport, NVC0_NEW_VIEWPORT },
394 { nvc0_validate_clip, NVC0_NEW_CLIP },
395 { nvc0_vertprog_validate, NVC0_NEW_VERTPROG },
396 { nvc0_tctlprog_validate, NVC0_NEW_TCTLPROG },
397 { nvc0_tevlprog_validate, NVC0_NEW_TEVLPROG },
398 { nvc0_gmtyprog_validate, NVC0_NEW_GMTYPROG },
399 { nvc0_fragprog_validate, NVC0_NEW_FRAGPROG },
400 { nvc0_constbufs_validate, NVC0_NEW_CONSTBUF },
401 { nvc0_validate_textures, NVC0_NEW_TEXTURES },
402 { nvc0_validate_samplers, NVC0_NEW_SAMPLERS },
403 { nvc0_vertex_arrays_validate, NVC0_NEW_VERTEX | NVC0_NEW_ARRAYS }
404 };
405 #define validate_list_len (sizeof(validate_list) / sizeof(validate_list[0]))
406
407 boolean
408 nvc0_state_validate(struct nvc0_context *nvc0)
409 {
410 unsigned i;
411 #if 0
412 if (nvc0->screen->cur_ctx != nvc0) /* FIXME: not everything is valid */
413 nvc0->dirty = 0xffffffff;
414 #endif
415 nvc0->screen->cur_ctx = nvc0;
416
417 if (nvc0->dirty) {
418 for (i = 0; i < validate_list_len; ++i) {
419 struct state_validate *validate = &validate_list[i];
420
421 if (nvc0->dirty & validate->states)
422 validate->func(nvc0);
423 }
424 nvc0->dirty = 0;
425 }
426
427 nvc0_bufctx_emit_relocs(nvc0);
428
429 return TRUE;
430 }