nvc0: avoid using magic numbers for the uniform_bo offsets
[mesa.git] / src / gallium / drivers / nouveau / nvc0 / nvc0_context.c
1 /*
2 * Copyright 2010 Christoph Bumiller
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #include "pipe/p_defines.h"
24 #include "util/u_framebuffer.h"
25
26 #include "nvc0/nvc0_context.h"
27 #include "nvc0/nvc0_screen.h"
28 #include "nvc0/nvc0_resource.h"
29
30 static void
31 nvc0_flush(struct pipe_context *pipe,
32 struct pipe_fence_handle **fence,
33 unsigned flags)
34 {
35 struct nvc0_context *nvc0 = nvc0_context(pipe);
36 struct nouveau_screen *screen = &nvc0->screen->base;
37
38 if (fence)
39 nouveau_fence_ref(screen->fence.current, (struct nouveau_fence **)fence);
40
41 PUSH_KICK(nvc0->base.pushbuf); /* fencing handled in kick_notify */
42
43 nouveau_context_update_frame_stats(&nvc0->base);
44 }
45
46 static void
47 nvc0_texture_barrier(struct pipe_context *pipe)
48 {
49 struct nouveau_pushbuf *push = nvc0_context(pipe)->base.pushbuf;
50
51 IMMED_NVC0(push, NVC0_3D(SERIALIZE), 0);
52 IMMED_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 0);
53 }
54
55 static void
56 nvc0_memory_barrier(struct pipe_context *pipe, unsigned flags)
57 {
58 struct nvc0_context *nvc0 = nvc0_context(pipe);
59 struct nouveau_pushbuf *push = nvc0->base.pushbuf;
60 int i, s;
61
62 if (flags & PIPE_BARRIER_MAPPED_BUFFER) {
63 for (i = 0; i < nvc0->num_vtxbufs; ++i) {
64 if (!nvc0->vtxbuf[i].buffer)
65 continue;
66 if (nvc0->vtxbuf[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
67 nvc0->base.vbo_dirty = true;
68 }
69
70 if (nvc0->idxbuf.buffer &&
71 nvc0->idxbuf.buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
72 nvc0->base.vbo_dirty = true;
73
74 for (s = 0; s < 5 && !nvc0->cb_dirty; ++s) {
75 uint32_t valid = nvc0->constbuf_valid[s];
76
77 while (valid && !nvc0->cb_dirty) {
78 const unsigned i = ffs(valid) - 1;
79 struct pipe_resource *res;
80
81 valid &= ~(1 << i);
82 if (nvc0->constbuf[s][i].user)
83 continue;
84
85 res = nvc0->constbuf[s][i].u.buf;
86 if (!res)
87 continue;
88
89 if (res->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
90 nvc0->cb_dirty = true;
91 }
92 }
93 }
94 if (flags & PIPE_BARRIER_SHADER_BUFFER) {
95 IMMED_NVC0(push, NVC0_3D(MEM_BARRIER), 0x1011);
96 }
97 }
98
99 static void
100 nvc0_context_unreference_resources(struct nvc0_context *nvc0)
101 {
102 unsigned s, i;
103
104 nouveau_bufctx_del(&nvc0->bufctx_3d);
105 nouveau_bufctx_del(&nvc0->bufctx);
106 nouveau_bufctx_del(&nvc0->bufctx_cp);
107
108 util_unreference_framebuffer_state(&nvc0->framebuffer);
109
110 for (i = 0; i < nvc0->num_vtxbufs; ++i)
111 pipe_resource_reference(&nvc0->vtxbuf[i].buffer, NULL);
112
113 pipe_resource_reference(&nvc0->idxbuf.buffer, NULL);
114
115 for (s = 0; s < 6; ++s) {
116 for (i = 0; i < nvc0->num_textures[s]; ++i)
117 pipe_sampler_view_reference(&nvc0->textures[s][i], NULL);
118
119 for (i = 0; i < NVC0_MAX_PIPE_CONSTBUFS; ++i)
120 if (!nvc0->constbuf[s][i].user)
121 pipe_resource_reference(&nvc0->constbuf[s][i].u.buf, NULL);
122 }
123
124 for (s = 0; s < 2; ++s) {
125 for (i = 0; i < NVC0_MAX_SURFACE_SLOTS; ++i)
126 pipe_surface_reference(&nvc0->surfaces[s][i], NULL);
127 }
128
129 for (s = 0; s < 6; ++s)
130 for (i = 0; i < NVC0_MAX_BUFFERS; ++i)
131 pipe_resource_reference(&nvc0->buffers[s][i].buffer, NULL);
132
133 for (i = 0; i < nvc0->num_tfbbufs; ++i)
134 pipe_so_target_reference(&nvc0->tfbbuf[i], NULL);
135
136 for (i = 0; i < nvc0->global_residents.size / sizeof(struct pipe_resource *);
137 ++i) {
138 struct pipe_resource **res = util_dynarray_element(
139 &nvc0->global_residents, struct pipe_resource *, i);
140 pipe_resource_reference(res, NULL);
141 }
142 util_dynarray_fini(&nvc0->global_residents);
143
144 if (nvc0->tcp_empty)
145 nvc0->base.pipe.delete_tcs_state(&nvc0->base.pipe, nvc0->tcp_empty);
146 }
147
148 static void
149 nvc0_destroy(struct pipe_context *pipe)
150 {
151 struct nvc0_context *nvc0 = nvc0_context(pipe);
152
153 if (nvc0->screen->cur_ctx == nvc0) {
154 nvc0->screen->cur_ctx = NULL;
155 nvc0->screen->save_state = nvc0->state;
156 nvc0->screen->save_state.tfb = NULL;
157 }
158
159 /* Unset bufctx, we don't want to revalidate any resources after the flush.
160 * Other contexts will always set their bufctx again on action calls.
161 */
162 nouveau_pushbuf_bufctx(nvc0->base.pushbuf, NULL);
163 nouveau_pushbuf_kick(nvc0->base.pushbuf, nvc0->base.pushbuf->channel);
164
165 nvc0_context_unreference_resources(nvc0);
166 nvc0_blitctx_destroy(nvc0);
167
168 nouveau_context_destroy(&nvc0->base);
169 }
170
171 void
172 nvc0_default_kick_notify(struct nouveau_pushbuf *push)
173 {
174 struct nvc0_screen *screen = push->user_priv;
175
176 if (screen) {
177 nouveau_fence_next(&screen->base);
178 nouveau_fence_update(&screen->base, true);
179 if (screen->cur_ctx)
180 screen->cur_ctx->state.flushed = true;
181 NOUVEAU_DRV_STAT(&screen->base, pushbuf_count, 1);
182 }
183 }
184
185 static int
186 nvc0_invalidate_resource_storage(struct nouveau_context *ctx,
187 struct pipe_resource *res,
188 int ref)
189 {
190 struct nvc0_context *nvc0 = nvc0_context(&ctx->pipe);
191 unsigned s, i;
192
193 if (res->bind & PIPE_BIND_RENDER_TARGET) {
194 for (i = 0; i < nvc0->framebuffer.nr_cbufs; ++i) {
195 if (nvc0->framebuffer.cbufs[i] &&
196 nvc0->framebuffer.cbufs[i]->texture == res) {
197 nvc0->dirty_3d |= NVC0_NEW_3D_FRAMEBUFFER;
198 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_FB);
199 if (!--ref)
200 return ref;
201 }
202 }
203 }
204 if (res->bind & PIPE_BIND_DEPTH_STENCIL) {
205 if (nvc0->framebuffer.zsbuf &&
206 nvc0->framebuffer.zsbuf->texture == res) {
207 nvc0->dirty_3d |= NVC0_NEW_3D_FRAMEBUFFER;
208 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_FB);
209 if (!--ref)
210 return ref;
211 }
212 }
213
214 if (res->target == PIPE_BUFFER) {
215 for (i = 0; i < nvc0->num_vtxbufs; ++i) {
216 if (nvc0->vtxbuf[i].buffer == res) {
217 nvc0->dirty_3d |= NVC0_NEW_3D_ARRAYS;
218 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_VTX);
219 if (!--ref)
220 return ref;
221 }
222 }
223
224 if (nvc0->idxbuf.buffer == res) {
225 nvc0->dirty_3d |= NVC0_NEW_3D_IDXBUF;
226 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_IDX);
227 if (!--ref)
228 return ref;
229 }
230
231 for (s = 0; s < 5; ++s) {
232 for (i = 0; i < nvc0->num_textures[s]; ++i) {
233 if (nvc0->textures[s][i] &&
234 nvc0->textures[s][i]->texture == res) {
235 nvc0->textures_dirty[s] |= 1 << i;
236 nvc0->dirty_3d |= NVC0_NEW_3D_TEXTURES;
237 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_TEX(s, i));
238 if (!--ref)
239 return ref;
240 }
241 }
242 }
243
244 for (s = 0; s < 6; ++s) {
245 for (i = 0; i < NVC0_MAX_PIPE_CONSTBUFS; ++i) {
246 if (!(nvc0->constbuf_valid[s] & (1 << i)))
247 continue;
248 if (!nvc0->constbuf[s][i].user &&
249 nvc0->constbuf[s][i].u.buf == res) {
250 nvc0->constbuf_dirty[s] |= 1 << i;
251 if (unlikely(s == 5)) {
252 nvc0->dirty_cp |= NVC0_NEW_CP_CONSTBUF;
253 nouveau_bufctx_reset(nvc0->bufctx_cp, NVC0_BIND_CP_CB(i));
254 } else {
255 nvc0->dirty_3d |= NVC0_NEW_3D_CONSTBUF;
256 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_CB(s, i));
257 }
258 if (!--ref)
259 return ref;
260 }
261 }
262 }
263
264 for (s = 0; s < 6; ++s) {
265 for (i = 0; i < NVC0_MAX_BUFFERS; ++i) {
266 if (nvc0->buffers[s][i].buffer == res) {
267 nvc0->buffers_dirty[s] |= 1 << i;
268 if (unlikely(s == 5)) {
269 nvc0->dirty_cp |= NVC0_NEW_CP_BUFFERS;
270 nouveau_bufctx_reset(nvc0->bufctx_cp, NVC0_BIND_CP_BUF);
271 } else {
272 nvc0->dirty_3d |= NVC0_NEW_3D_BUFFERS;
273 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_BUF);
274 }
275 if (!--ref)
276 return ref;
277 }
278 }
279 }
280 }
281
282 return ref;
283 }
284
285 static void
286 nvc0_context_get_sample_position(struct pipe_context *, unsigned, unsigned,
287 float *);
288
289 struct pipe_context *
290 nvc0_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags)
291 {
292 struct nvc0_screen *screen = nvc0_screen(pscreen);
293 struct nvc0_context *nvc0;
294 struct pipe_context *pipe;
295 int ret;
296 uint32_t flags;
297
298 nvc0 = CALLOC_STRUCT(nvc0_context);
299 if (!nvc0)
300 return NULL;
301 pipe = &nvc0->base.pipe;
302
303 if (!nvc0_blitctx_create(nvc0))
304 goto out_err;
305
306 nvc0->base.pushbuf = screen->base.pushbuf;
307 nvc0->base.client = screen->base.client;
308
309 ret = nouveau_bufctx_new(screen->base.client, 2, &nvc0->bufctx);
310 if (!ret)
311 ret = nouveau_bufctx_new(screen->base.client, NVC0_BIND_3D_COUNT,
312 &nvc0->bufctx_3d);
313 if (!ret)
314 ret = nouveau_bufctx_new(screen->base.client, NVC0_BIND_CP_COUNT,
315 &nvc0->bufctx_cp);
316 if (ret)
317 goto out_err;
318
319 nvc0->screen = screen;
320 nvc0->base.screen = &screen->base;
321
322 pipe->screen = pscreen;
323 pipe->priv = priv;
324
325 pipe->destroy = nvc0_destroy;
326
327 pipe->draw_vbo = nvc0_draw_vbo;
328 pipe->clear = nvc0_clear;
329 pipe->launch_grid = (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) ?
330 nve4_launch_grid : nvc0_launch_grid;
331
332 pipe->flush = nvc0_flush;
333 pipe->texture_barrier = nvc0_texture_barrier;
334 pipe->memory_barrier = nvc0_memory_barrier;
335 pipe->get_sample_position = nvc0_context_get_sample_position;
336
337 nouveau_context_init(&nvc0->base);
338 nvc0_init_query_functions(nvc0);
339 nvc0_init_surface_functions(nvc0);
340 nvc0_init_state_functions(nvc0);
341 nvc0_init_transfer_functions(nvc0);
342 nvc0_init_resource_functions(pipe);
343
344 nvc0->base.invalidate_resource_storage = nvc0_invalidate_resource_storage;
345
346 pipe->create_video_codec = nvc0_create_decoder;
347 pipe->create_video_buffer = nvc0_video_buffer_create;
348
349 /* shader builtin library is per-screen, but we need a context for m2mf */
350 nvc0_program_library_upload(nvc0);
351 nvc0_program_init_tcp_empty(nvc0);
352 if (!nvc0->tcp_empty)
353 goto out_err;
354 /* set the empty tctl prog on next draw in case one is never set */
355 nvc0->dirty_3d |= NVC0_NEW_3D_TCTLPROG;
356
357 /* Do not bind the COMPUTE driver constbuf at screen initialization because
358 * CBs are aliased between 3D and COMPUTE, but make sure it will be bound if
359 * a grid is launched later. */
360 nvc0->dirty_cp |= NVC0_NEW_CP_DRIVERCONST;
361
362 /* now that there are no more opportunities for errors, set the current
363 * context if there isn't already one.
364 */
365 if (!screen->cur_ctx) {
366 nvc0->state = screen->save_state;
367 screen->cur_ctx = nvc0;
368 nouveau_pushbuf_bufctx(screen->base.pushbuf, nvc0->bufctx);
369 }
370 screen->base.pushbuf->kick_notify = nvc0_default_kick_notify;
371
372 /* add permanently resident buffers to bufctxts */
373
374 flags = NV_VRAM_DOMAIN(&screen->base) | NOUVEAU_BO_RD;
375
376 BCTX_REFN_bo(nvc0->bufctx_3d, 3D_SCREEN, flags, screen->text);
377 BCTX_REFN_bo(nvc0->bufctx_3d, 3D_SCREEN, flags, screen->uniform_bo);
378 BCTX_REFN_bo(nvc0->bufctx_3d, 3D_SCREEN, flags, screen->txc);
379 if (screen->compute) {
380 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->text);
381 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->uniform_bo);
382 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->txc);
383 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->parm);
384 }
385
386 flags = NV_VRAM_DOMAIN(&screen->base) | NOUVEAU_BO_RDWR;
387
388 if (screen->poly_cache)
389 BCTX_REFN_bo(nvc0->bufctx_3d, 3D_SCREEN, flags, screen->poly_cache);
390 if (screen->compute)
391 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->tls);
392
393 flags = NOUVEAU_BO_GART | NOUVEAU_BO_WR;
394
395 BCTX_REFN_bo(nvc0->bufctx_3d, 3D_SCREEN, flags, screen->fence.bo);
396 BCTX_REFN_bo(nvc0->bufctx, FENCE, flags, screen->fence.bo);
397 if (screen->compute)
398 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->fence.bo);
399
400 nvc0->base.scratch.bo_size = 2 << 20;
401
402 memset(nvc0->tex_handles, ~0, sizeof(nvc0->tex_handles));
403
404 util_dynarray_init(&nvc0->global_residents);
405
406 return pipe;
407
408 out_err:
409 if (nvc0) {
410 if (nvc0->bufctx_3d)
411 nouveau_bufctx_del(&nvc0->bufctx_3d);
412 if (nvc0->bufctx_cp)
413 nouveau_bufctx_del(&nvc0->bufctx_cp);
414 if (nvc0->bufctx)
415 nouveau_bufctx_del(&nvc0->bufctx);
416 FREE(nvc0->blit);
417 FREE(nvc0);
418 }
419 return NULL;
420 }
421
422 void
423 nvc0_bufctx_fence(struct nvc0_context *nvc0, struct nouveau_bufctx *bufctx,
424 bool on_flush)
425 {
426 struct nouveau_list *list = on_flush ? &bufctx->current : &bufctx->pending;
427 struct nouveau_list *it;
428 NOUVEAU_DRV_STAT_IFD(unsigned count = 0);
429
430 for (it = list->next; it != list; it = it->next) {
431 struct nouveau_bufref *ref = (struct nouveau_bufref *)it;
432 struct nv04_resource *res = ref->priv;
433 if (res)
434 nvc0_resource_validate(res, (unsigned)ref->priv_data);
435 NOUVEAU_DRV_STAT_IFD(count++);
436 }
437 NOUVEAU_DRV_STAT(&nvc0->screen->base, resource_validate_count, count);
438 }
439
440 static void
441 nvc0_context_get_sample_position(struct pipe_context *pipe,
442 unsigned sample_count, unsigned sample_index,
443 float *xy)
444 {
445 static const uint8_t ms1[1][2] = { { 0x8, 0x8 } };
446 static const uint8_t ms2[2][2] = {
447 { 0x4, 0x4 }, { 0xc, 0xc } }; /* surface coords (0,0), (1,0) */
448 static const uint8_t ms4[4][2] = {
449 { 0x6, 0x2 }, { 0xe, 0x6 }, /* (0,0), (1,0) */
450 { 0x2, 0xa }, { 0xa, 0xe } }; /* (0,1), (1,1) */
451 static const uint8_t ms8[8][2] = {
452 { 0x1, 0x7 }, { 0x5, 0x3 }, /* (0,0), (1,0) */
453 { 0x3, 0xd }, { 0x7, 0xb }, /* (0,1), (1,1) */
454 { 0x9, 0x5 }, { 0xf, 0x1 }, /* (2,0), (3,0) */
455 { 0xb, 0xf }, { 0xd, 0x9 } }; /* (2,1), (3,1) */
456 #if 0
457 /* NOTE: there are alternative modes for MS2 and MS8, currently not used */
458 static const uint8_t ms8_alt[8][2] = {
459 { 0x9, 0x5 }, { 0x7, 0xb }, /* (2,0), (1,1) */
460 { 0xd, 0x9 }, { 0x5, 0x3 }, /* (3,1), (1,0) */
461 { 0x3, 0xd }, { 0x1, 0x7 }, /* (0,1), (0,0) */
462 { 0xb, 0xf }, { 0xf, 0x1 } }; /* (2,1), (3,0) */
463 #endif
464
465 const uint8_t (*ptr)[2];
466
467 switch (sample_count) {
468 case 0:
469 case 1: ptr = ms1; break;
470 case 2: ptr = ms2; break;
471 case 4: ptr = ms4; break;
472 case 8: ptr = ms8; break;
473 default:
474 assert(0);
475 return; /* bad sample count -> undefined locations */
476 }
477 xy[0] = ptr[sample_index][0] * 0.0625f;
478 xy[1] = ptr[sample_index][1] * 0.0625f;
479 }