OSDN Git Service

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