Merge remote-tracking branch 'mesa-public/master' into vulkan
[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 |= NVC0_NEW_FRAMEBUFFER;
198 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_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 |= NVC0_NEW_FRAMEBUFFER;
208 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_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 |= NVC0_NEW_ARRAYS;
218 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_VTX);
219 if (!--ref)
220 return ref;
221 }
222 }
223
224 if (nvc0->idxbuf.buffer == res) {
225 nvc0->dirty |= NVC0_NEW_IDXBUF;
226 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_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 |= NVC0_NEW_TEXTURES;
237 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_TEX(s, i));
238 if (!--ref)
239 return ref;
240 }
241 }
242 }
243
244 for (s = 0; s < 5; ++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->dirty |= NVC0_NEW_CONSTBUF;
251 nvc0->constbuf_dirty[s] |= 1 << i;
252 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_CB(s, i));
253 if (!--ref)
254 return ref;
255 }
256 }
257 }
258
259 for (s = 0; s < 5; ++s) {
260 for (i = 0; i < NVC0_MAX_BUFFERS; ++i) {
261 if (nvc0->buffers[s][i].buffer == res) {
262 nvc0->buffers_dirty[s] |= 1 << i;
263 nvc0->dirty |= NVC0_NEW_BUFFERS;
264 nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_BUF);
265 if (!--ref)
266 return ref;
267 }
268 }
269 }
270 }
271
272 return ref;
273 }
274
275 static void
276 nvc0_context_get_sample_position(struct pipe_context *, unsigned, unsigned,
277 float *);
278
279 struct pipe_context *
280 nvc0_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags)
281 {
282 struct nvc0_screen *screen = nvc0_screen(pscreen);
283 struct nvc0_context *nvc0;
284 struct pipe_context *pipe;
285 int ret;
286 uint32_t flags;
287
288 nvc0 = CALLOC_STRUCT(nvc0_context);
289 if (!nvc0)
290 return NULL;
291 pipe = &nvc0->base.pipe;
292
293 if (!nvc0_blitctx_create(nvc0))
294 goto out_err;
295
296 nvc0->base.pushbuf = screen->base.pushbuf;
297 nvc0->base.client = screen->base.client;
298
299 ret = nouveau_bufctx_new(screen->base.client, 2, &nvc0->bufctx);
300 if (!ret)
301 ret = nouveau_bufctx_new(screen->base.client, NVC0_BIND_3D_COUNT,
302 &nvc0->bufctx_3d);
303 if (!ret)
304 ret = nouveau_bufctx_new(screen->base.client, NVC0_BIND_CP_COUNT,
305 &nvc0->bufctx_cp);
306 if (ret)
307 goto out_err;
308
309 nvc0->screen = screen;
310 nvc0->base.screen = &screen->base;
311
312 pipe->screen = pscreen;
313 pipe->priv = priv;
314
315 pipe->destroy = nvc0_destroy;
316
317 pipe->draw_vbo = nvc0_draw_vbo;
318 pipe->clear = nvc0_clear;
319 pipe->launch_grid = (nvc0->screen->base.class_3d >= NVE4_3D_CLASS) ?
320 nve4_launch_grid : nvc0_launch_grid;
321
322 pipe->flush = nvc0_flush;
323 pipe->texture_barrier = nvc0_texture_barrier;
324 pipe->memory_barrier = nvc0_memory_barrier;
325 pipe->get_sample_position = nvc0_context_get_sample_position;
326
327 nouveau_context_init(&nvc0->base);
328 nvc0_init_query_functions(nvc0);
329 nvc0_init_surface_functions(nvc0);
330 nvc0_init_state_functions(nvc0);
331 nvc0_init_transfer_functions(nvc0);
332 nvc0_init_resource_functions(pipe);
333
334 nvc0->base.invalidate_resource_storage = nvc0_invalidate_resource_storage;
335
336 pipe->create_video_codec = nvc0_create_decoder;
337 pipe->create_video_buffer = nvc0_video_buffer_create;
338
339 /* shader builtin library is per-screen, but we need a context for m2mf */
340 nvc0_program_library_upload(nvc0);
341 nvc0_program_init_tcp_empty(nvc0);
342 if (!nvc0->tcp_empty)
343 goto out_err;
344 /* set the empty tctl prog on next draw in case one is never set */
345 nvc0->dirty |= NVC0_NEW_TCTLPROG;
346
347 /* now that there are no more opportunities for errors, set the current
348 * context if there isn't already one.
349 */
350 if (!screen->cur_ctx) {
351 nvc0->state = screen->save_state;
352 screen->cur_ctx = nvc0;
353 nouveau_pushbuf_bufctx(screen->base.pushbuf, nvc0->bufctx);
354 }
355 screen->base.pushbuf->kick_notify = nvc0_default_kick_notify;
356
357 /* add permanently resident buffers to bufctxts */
358
359 flags = NV_VRAM_DOMAIN(&screen->base) | NOUVEAU_BO_RD;
360
361 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->text);
362 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->uniform_bo);
363 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->txc);
364 if (screen->compute) {
365 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->text);
366 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->txc);
367 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->parm);
368 }
369
370 flags = NV_VRAM_DOMAIN(&screen->base) | NOUVEAU_BO_RDWR;
371
372 if (screen->poly_cache)
373 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->poly_cache);
374 if (screen->compute)
375 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->tls);
376
377 flags = NOUVEAU_BO_GART | NOUVEAU_BO_WR;
378
379 BCTX_REFN_bo(nvc0->bufctx_3d, SCREEN, flags, screen->fence.bo);
380 BCTX_REFN_bo(nvc0->bufctx, FENCE, flags, screen->fence.bo);
381 if (screen->compute)
382 BCTX_REFN_bo(nvc0->bufctx_cp, CP_SCREEN, flags, screen->fence.bo);
383
384 nvc0->base.scratch.bo_size = 2 << 20;
385
386 memset(nvc0->tex_handles, ~0, sizeof(nvc0->tex_handles));
387
388 util_dynarray_init(&nvc0->global_residents);
389
390 return pipe;
391
392 out_err:
393 if (nvc0) {
394 if (nvc0->bufctx_3d)
395 nouveau_bufctx_del(&nvc0->bufctx_3d);
396 if (nvc0->bufctx_cp)
397 nouveau_bufctx_del(&nvc0->bufctx_cp);
398 if (nvc0->bufctx)
399 nouveau_bufctx_del(&nvc0->bufctx);
400 FREE(nvc0->blit);
401 FREE(nvc0);
402 }
403 return NULL;
404 }
405
406 void
407 nvc0_bufctx_fence(struct nvc0_context *nvc0, struct nouveau_bufctx *bufctx,
408 bool on_flush)
409 {
410 struct nouveau_list *list = on_flush ? &bufctx->current : &bufctx->pending;
411 struct nouveau_list *it;
412 NOUVEAU_DRV_STAT_IFD(unsigned count = 0);
413
414 for (it = list->next; it != list; it = it->next) {
415 struct nouveau_bufref *ref = (struct nouveau_bufref *)it;
416 struct nv04_resource *res = ref->priv;
417 if (res)
418 nvc0_resource_validate(res, (unsigned)ref->priv_data);
419 NOUVEAU_DRV_STAT_IFD(count++);
420 }
421 NOUVEAU_DRV_STAT(&nvc0->screen->base, resource_validate_count, count);
422 }
423
424 static void
425 nvc0_context_get_sample_position(struct pipe_context *pipe,
426 unsigned sample_count, unsigned sample_index,
427 float *xy)
428 {
429 static const uint8_t ms1[1][2] = { { 0x8, 0x8 } };
430 static const uint8_t ms2[2][2] = {
431 { 0x4, 0x4 }, { 0xc, 0xc } }; /* surface coords (0,0), (1,0) */
432 static const uint8_t ms4[4][2] = {
433 { 0x6, 0x2 }, { 0xe, 0x6 }, /* (0,0), (1,0) */
434 { 0x2, 0xa }, { 0xa, 0xe } }; /* (0,1), (1,1) */
435 static const uint8_t ms8[8][2] = {
436 { 0x1, 0x7 }, { 0x5, 0x3 }, /* (0,0), (1,0) */
437 { 0x3, 0xd }, { 0x7, 0xb }, /* (0,1), (1,1) */
438 { 0x9, 0x5 }, { 0xf, 0x1 }, /* (2,0), (3,0) */
439 { 0xb, 0xf }, { 0xd, 0x9 } }; /* (2,1), (3,1) */
440 #if 0
441 /* NOTE: there are alternative modes for MS2 and MS8, currently not used */
442 static const uint8_t ms8_alt[8][2] = {
443 { 0x9, 0x5 }, { 0x7, 0xb }, /* (2,0), (1,1) */
444 { 0xd, 0x9 }, { 0x5, 0x3 }, /* (3,1), (1,0) */
445 { 0x3, 0xd }, { 0x1, 0x7 }, /* (0,1), (0,0) */
446 { 0xb, 0xf }, { 0xf, 0x1 } }; /* (2,1), (3,0) */
447 #endif
448
449 const uint8_t (*ptr)[2];
450
451 switch (sample_count) {
452 case 0:
453 case 1: ptr = ms1; break;
454 case 2: ptr = ms2; break;
455 case 4: ptr = ms4; break;
456 case 8: ptr = ms8; break;
457 default:
458 assert(0);
459 return; /* bad sample count -> undefined locations */
460 }
461 xy[0] = ptr[sample_index][0] * 0.0625f;
462 xy[1] = ptr[sample_index][1] * 0.0625f;
463 }