• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "nv50/nv50_context.h"
27 #include "nv50/nv50_screen.h"
28 #include "nv50/nv50_resource.h"
29 
30 static void
nv50_flush(struct pipe_context * pipe,struct pipe_fence_handle ** fence,unsigned flags)31 nv50_flush(struct pipe_context *pipe,
32            struct pipe_fence_handle **fence,
33            unsigned flags)
34 {
35    struct nouveau_screen *screen = nouveau_screen(pipe->screen);
36 
37    if (fence)
38       nouveau_fence_ref(screen->fence.current, (struct nouveau_fence **)fence);
39 
40    PUSH_KICK(screen->pushbuf);
41 
42    nouveau_context_update_frame_stats(nouveau_context(pipe));
43 }
44 
45 static void
nv50_texture_barrier(struct pipe_context * pipe,unsigned flags)46 nv50_texture_barrier(struct pipe_context *pipe, unsigned flags)
47 {
48    struct nouveau_pushbuf *push = nv50_context(pipe)->base.pushbuf;
49 
50    BEGIN_NV04(push, SUBC_3D(NV50_GRAPH_SERIALIZE), 1);
51    PUSH_DATA (push, 0);
52    BEGIN_NV04(push, NV50_3D(TEX_CACHE_CTL), 1);
53    PUSH_DATA (push, 0x20);
54 }
55 
56 static void
nv50_memory_barrier(struct pipe_context * pipe,unsigned flags)57 nv50_memory_barrier(struct pipe_context *pipe, unsigned flags)
58 {
59    struct nv50_context *nv50 = nv50_context(pipe);
60    int i, s;
61 
62    if (flags & PIPE_BARRIER_MAPPED_BUFFER) {
63       for (i = 0; i < nv50->num_vtxbufs; ++i) {
64          if (!nv50->vtxbuf[i].buffer)
65             continue;
66          if (nv50->vtxbuf[i].buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
67             nv50->base.vbo_dirty = true;
68       }
69 
70       if (nv50->idxbuf.buffer &&
71           nv50->idxbuf.buffer->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
72          nv50->base.vbo_dirty = true;
73 
74       for (s = 0; s < 3 && !nv50->cb_dirty; ++s) {
75          uint32_t valid = nv50->constbuf_valid[s];
76 
77          while (valid && !nv50->cb_dirty) {
78             const unsigned i = ffs(valid) - 1;
79             struct pipe_resource *res;
80 
81             valid &= ~(1 << i);
82             if (nv50->constbuf[s][i].user)
83                continue;
84 
85             res = nv50->constbuf[s][i].u.buf;
86             if (!res)
87                continue;
88 
89             if (res->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
90                nv50->cb_dirty = true;
91          }
92       }
93    }
94 }
95 
96 static void
nv50_emit_string_marker(struct pipe_context * pipe,const char * str,int len)97 nv50_emit_string_marker(struct pipe_context *pipe, const char *str, int len)
98 {
99    struct nouveau_pushbuf *push = nv50_context(pipe)->base.pushbuf;
100    int string_words = len / 4;
101    int data_words;
102 
103    if (len <= 0)
104       return;
105    string_words = MIN2(string_words, NV04_PFIFO_MAX_PACKET_LEN);
106    if (string_words == NV04_PFIFO_MAX_PACKET_LEN)
107       data_words = string_words;
108    else
109       data_words = string_words + !!(len & 3);
110    BEGIN_NI04(push, SUBC_3D(NV04_GRAPH_NOP), data_words);
111    if (string_words)
112       PUSH_DATAp(push, str, string_words);
113    if (string_words != data_words) {
114       int data = 0;
115       memcpy(&data, &str[string_words * 4], len & 3);
116       PUSH_DATA (push, data);
117    }
118 }
119 
120 void
nv50_default_kick_notify(struct nouveau_pushbuf * push)121 nv50_default_kick_notify(struct nouveau_pushbuf *push)
122 {
123    struct nv50_screen *screen = push->user_priv;
124 
125    if (screen) {
126       nouveau_fence_next(&screen->base);
127       nouveau_fence_update(&screen->base, true);
128       if (screen->cur_ctx)
129          screen->cur_ctx->state.flushed = true;
130    }
131 }
132 
133 static void
nv50_context_unreference_resources(struct nv50_context * nv50)134 nv50_context_unreference_resources(struct nv50_context *nv50)
135 {
136    unsigned s, i;
137 
138    nouveau_bufctx_del(&nv50->bufctx_3d);
139    nouveau_bufctx_del(&nv50->bufctx);
140    nouveau_bufctx_del(&nv50->bufctx_cp);
141 
142    util_unreference_framebuffer_state(&nv50->framebuffer);
143 
144    assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
145    for (i = 0; i < nv50->num_vtxbufs; ++i)
146       pipe_resource_reference(&nv50->vtxbuf[i].buffer, NULL);
147 
148    pipe_resource_reference(&nv50->idxbuf.buffer, NULL);
149 
150    for (s = 0; s < 3; ++s) {
151       assert(nv50->num_textures[s] <= PIPE_MAX_SAMPLERS);
152       for (i = 0; i < nv50->num_textures[s]; ++i)
153          pipe_sampler_view_reference(&nv50->textures[s][i], NULL);
154 
155       for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i)
156          if (!nv50->constbuf[s][i].user)
157             pipe_resource_reference(&nv50->constbuf[s][i].u.buf, NULL);
158    }
159 
160    for (i = 0; i < nv50->global_residents.size / sizeof(struct pipe_resource *);
161         ++i) {
162       struct pipe_resource **res = util_dynarray_element(
163          &nv50->global_residents, struct pipe_resource *, i);
164       pipe_resource_reference(res, NULL);
165    }
166    util_dynarray_fini(&nv50->global_residents);
167 }
168 
169 static void
nv50_destroy(struct pipe_context * pipe)170 nv50_destroy(struct pipe_context *pipe)
171 {
172    struct nv50_context *nv50 = nv50_context(pipe);
173 
174    if (nv50->screen->cur_ctx == nv50) {
175       nv50->screen->cur_ctx = NULL;
176       /* Save off the state in case another context gets created */
177       nv50->screen->save_state = nv50->state;
178    }
179    nouveau_pushbuf_bufctx(nv50->base.pushbuf, NULL);
180    nouveau_pushbuf_kick(nv50->base.pushbuf, nv50->base.pushbuf->channel);
181 
182    nv50_context_unreference_resources(nv50);
183 
184    FREE(nv50->blit);
185 
186    nouveau_context_destroy(&nv50->base);
187 }
188 
189 static int
nv50_invalidate_resource_storage(struct nouveau_context * ctx,struct pipe_resource * res,int ref)190 nv50_invalidate_resource_storage(struct nouveau_context *ctx,
191                                  struct pipe_resource *res,
192                                  int ref)
193 {
194    struct nv50_context *nv50 = nv50_context(&ctx->pipe);
195    unsigned bind = res->bind ? res->bind : PIPE_BIND_VERTEX_BUFFER;
196    unsigned s, i;
197 
198    if (bind & PIPE_BIND_RENDER_TARGET) {
199       assert(nv50->framebuffer.nr_cbufs <= PIPE_MAX_COLOR_BUFS);
200       for (i = 0; i < nv50->framebuffer.nr_cbufs; ++i) {
201          if (nv50->framebuffer.cbufs[i] &&
202              nv50->framebuffer.cbufs[i]->texture == res) {
203             nv50->dirty_3d |= NV50_NEW_3D_FRAMEBUFFER;
204             nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_FB);
205             if (!--ref)
206                return ref;
207          }
208       }
209    }
210    if (bind & PIPE_BIND_DEPTH_STENCIL) {
211       if (nv50->framebuffer.zsbuf &&
212           nv50->framebuffer.zsbuf->texture == res) {
213          nv50->dirty_3d |= NV50_NEW_3D_FRAMEBUFFER;
214          nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_FB);
215          if (!--ref)
216             return ref;
217       }
218    }
219 
220    if (bind & (PIPE_BIND_VERTEX_BUFFER |
221                PIPE_BIND_INDEX_BUFFER |
222                PIPE_BIND_CONSTANT_BUFFER |
223                PIPE_BIND_STREAM_OUTPUT |
224                PIPE_BIND_SAMPLER_VIEW)) {
225 
226       assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
227       for (i = 0; i < nv50->num_vtxbufs; ++i) {
228          if (nv50->vtxbuf[i].buffer == res) {
229             nv50->dirty_3d |= NV50_NEW_3D_ARRAYS;
230             nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_VERTEX);
231             if (!--ref)
232                return ref;
233          }
234       }
235 
236       if (nv50->idxbuf.buffer == res) {
237          /* Just rebind to the bufctx as there is no separate dirty bit */
238          nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_INDEX);
239          BCTX_REFN(nv50->bufctx_3d, 3D_INDEX, nv04_resource(res), RD);
240          if (!--ref)
241             return ref;
242       }
243 
244       for (s = 0; s < 3; ++s) {
245       assert(nv50->num_textures[s] <= PIPE_MAX_SAMPLERS);
246       for (i = 0; i < nv50->num_textures[s]; ++i) {
247          if (nv50->textures[s][i] &&
248              nv50->textures[s][i]->texture == res) {
249             nv50->dirty_3d |= NV50_NEW_3D_TEXTURES;
250             nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_TEXTURES);
251             if (!--ref)
252                return ref;
253          }
254       }
255       }
256 
257       for (s = 0; s < 3; ++s) {
258       for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i) {
259          if (!(nv50->constbuf_valid[s] & (1 << i)))
260             continue;
261          if (!nv50->constbuf[s][i].user &&
262              nv50->constbuf[s][i].u.buf == res) {
263             nv50->dirty_3d |= NV50_NEW_3D_CONSTBUF;
264             nv50->constbuf_dirty[s] |= 1 << i;
265             nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_3D_CB(s, i));
266             if (!--ref)
267                return ref;
268          }
269       }
270       }
271    }
272 
273    return ref;
274 }
275 
276 static void
277 nv50_context_get_sample_position(struct pipe_context *, unsigned, unsigned,
278                                  float *);
279 
280 struct pipe_context *
nv50_create(struct pipe_screen * pscreen,void * priv,unsigned ctxflags)281 nv50_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags)
282 {
283    struct nv50_screen *screen = nv50_screen(pscreen);
284    struct nv50_context *nv50;
285    struct pipe_context *pipe;
286    int ret;
287    uint32_t flags;
288 
289    nv50 = CALLOC_STRUCT(nv50_context);
290    if (!nv50)
291       return NULL;
292    pipe = &nv50->base.pipe;
293 
294    if (!nv50_blitctx_create(nv50))
295       goto out_err;
296 
297    nv50->base.pushbuf = screen->base.pushbuf;
298    nv50->base.client = screen->base.client;
299 
300    ret = nouveau_bufctx_new(screen->base.client, 2, &nv50->bufctx);
301    if (!ret)
302       ret = nouveau_bufctx_new(screen->base.client, NV50_BIND_3D_COUNT,
303                                &nv50->bufctx_3d);
304    if (!ret)
305       ret = nouveau_bufctx_new(screen->base.client, NV50_BIND_CP_COUNT,
306                                &nv50->bufctx_cp);
307    if (ret)
308       goto out_err;
309 
310    nv50->base.screen    = &screen->base;
311    nv50->base.copy_data = nv50_m2mf_copy_linear;
312    nv50->base.push_data = nv50_sifc_linear_u8;
313    nv50->base.push_cb   = nv50_cb_push;
314 
315    nv50->screen = screen;
316    pipe->screen = pscreen;
317    pipe->priv = priv;
318 
319    pipe->destroy = nv50_destroy;
320 
321    pipe->draw_vbo = nv50_draw_vbo;
322    pipe->clear = nv50_clear;
323    pipe->launch_grid = nv50_launch_grid;
324 
325    pipe->flush = nv50_flush;
326    pipe->texture_barrier = nv50_texture_barrier;
327    pipe->memory_barrier = nv50_memory_barrier;
328    pipe->get_sample_position = nv50_context_get_sample_position;
329    pipe->emit_string_marker = nv50_emit_string_marker;
330 
331    if (!screen->cur_ctx) {
332       /* Restore the last context's state here, normally handled during
333        * context switch
334        */
335       nv50->state = screen->save_state;
336       screen->cur_ctx = nv50;
337       nouveau_pushbuf_bufctx(screen->base.pushbuf, nv50->bufctx);
338    }
339    nv50->base.pushbuf->kick_notify = nv50_default_kick_notify;
340 
341    nouveau_context_init(&nv50->base);
342    nv50_init_query_functions(nv50);
343    nv50_init_surface_functions(nv50);
344    nv50_init_state_functions(nv50);
345    nv50_init_resource_functions(pipe);
346 
347    nv50->base.invalidate_resource_storage = nv50_invalidate_resource_storage;
348 
349    if (screen->base.device->chipset < 0x84 ||
350        debug_get_bool_option("NOUVEAU_PMPEG", false)) {
351       /* PMPEG */
352       nouveau_context_init_vdec(&nv50->base);
353    } else if (screen->base.device->chipset < 0x98 ||
354               screen->base.device->chipset == 0xa0) {
355       /* VP2 */
356       pipe->create_video_codec = nv84_create_decoder;
357       pipe->create_video_buffer = nv84_video_buffer_create;
358    } else {
359       /* VP3/4 */
360       pipe->create_video_codec = nv98_create_decoder;
361       pipe->create_video_buffer = nv98_video_buffer_create;
362    }
363 
364    flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD;
365 
366    BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->code);
367    BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->uniforms);
368    BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->txc);
369    BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->stack_bo);
370    if (screen->compute) {
371       BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->code);
372       BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->txc);
373       BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->stack_bo);
374    }
375 
376    flags = NOUVEAU_BO_GART | NOUVEAU_BO_WR;
377 
378    BCTX_REFN_bo(nv50->bufctx_3d, 3D_SCREEN, flags, screen->fence.bo);
379    BCTX_REFN_bo(nv50->bufctx, FENCE, flags, screen->fence.bo);
380    if (screen->compute)
381       BCTX_REFN_bo(nv50->bufctx_cp, CP_SCREEN, flags, screen->fence.bo);
382 
383    nv50->base.scratch.bo_size = 2 << 20;
384 
385    util_dynarray_init(&nv50->global_residents);
386 
387    return pipe;
388 
389 out_err:
390    if (nv50->bufctx_3d)
391       nouveau_bufctx_del(&nv50->bufctx_3d);
392    if (nv50->bufctx_cp)
393       nouveau_bufctx_del(&nv50->bufctx_cp);
394    if (nv50->bufctx)
395       nouveau_bufctx_del(&nv50->bufctx);
396    FREE(nv50->blit);
397    FREE(nv50);
398    return NULL;
399 }
400 
401 void
nv50_bufctx_fence(struct nouveau_bufctx * bufctx,bool on_flush)402 nv50_bufctx_fence(struct nouveau_bufctx *bufctx, bool on_flush)
403 {
404    struct nouveau_list *list = on_flush ? &bufctx->current : &bufctx->pending;
405    struct nouveau_list *it;
406 
407    for (it = list->next; it != list; it = it->next) {
408       struct nouveau_bufref *ref = (struct nouveau_bufref *)it;
409       struct nv04_resource *res = ref->priv;
410       if (res)
411          nv50_resource_validate(res, (unsigned)ref->priv_data);
412    }
413 }
414 
415 static void
nv50_context_get_sample_position(struct pipe_context * pipe,unsigned sample_count,unsigned sample_index,float * xy)416 nv50_context_get_sample_position(struct pipe_context *pipe,
417                                  unsigned sample_count, unsigned sample_index,
418                                  float *xy)
419 {
420    static const uint8_t ms1[1][2] = { { 0x8, 0x8 } };
421    static const uint8_t ms2[2][2] = {
422       { 0x4, 0x4 }, { 0xc, 0xc } }; /* surface coords (0,0), (1,0) */
423    static const uint8_t ms4[4][2] = {
424       { 0x6, 0x2 }, { 0xe, 0x6 },   /* (0,0), (1,0) */
425       { 0x2, 0xa }, { 0xa, 0xe } }; /* (0,1), (1,1) */
426    static const uint8_t ms8[8][2] = {
427       { 0x1, 0x7 }, { 0x5, 0x3 },   /* (0,0), (1,0) */
428       { 0x3, 0xd }, { 0x7, 0xb },   /* (0,1), (1,1) */
429       { 0x9, 0x5 }, { 0xf, 0x1 },   /* (2,0), (3,0) */
430       { 0xb, 0xf }, { 0xd, 0x9 } }; /* (2,1), (3,1) */
431 #if 0
432    /* NOTE: there are alternative modes for MS2 and MS8, currently not used */
433    static const uint8_t ms8_alt[8][2] = {
434       { 0x9, 0x5 }, { 0x7, 0xb },   /* (2,0), (1,1) */
435       { 0xd, 0x9 }, { 0x5, 0x3 },   /* (3,1), (1,0) */
436       { 0x3, 0xd }, { 0x1, 0x7 },   /* (0,1), (0,0) */
437       { 0xb, 0xf }, { 0xf, 0x1 } }; /* (2,1), (3,0) */
438 #endif
439 
440    const uint8_t (*ptr)[2];
441 
442    switch (sample_count) {
443    case 0:
444    case 1: ptr = ms1; break;
445    case 2: ptr = ms2; break;
446    case 4: ptr = ms4; break;
447    case 8: ptr = ms8; break;
448    default:
449       assert(0);
450       return; /* bad sample count -> undefined locations */
451    }
452    xy[0] = ptr[sample_index][0] * 0.0625f;
453    xy[1] = ptr[sample_index][1] * 0.0625f;
454 }
455