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