OSDN Git Service

1a53579b49d4d2459b0bb106ca03d0a3c112ec0e
[android-x86/external-mesa.git] / src / gallium / drivers / nouveau / nv50 / nv50_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 "nv50/nv50_context.h"
27 #include "nv50/nv50_screen.h"
28 #include "nv50/nv50_resource.h"
29
30 static void
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
46 nv50_texture_barrier(struct pipe_context *pipe)
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
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 void
97 nv50_default_kick_notify(struct nouveau_pushbuf *push)
98 {
99    struct nv50_screen *screen = push->user_priv;
100
101    if (screen) {
102       nouveau_fence_next(&screen->base);
103       nouveau_fence_update(&screen->base, TRUE);
104       if (screen->cur_ctx)
105          screen->cur_ctx->state.flushed = TRUE;
106    }
107 }
108
109 static void
110 nv50_context_unreference_resources(struct nv50_context *nv50)
111 {
112    unsigned s, i;
113
114    nouveau_bufctx_del(&nv50->bufctx_3d);
115    nouveau_bufctx_del(&nv50->bufctx);
116
117    util_unreference_framebuffer_state(&nv50->framebuffer);
118
119    assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
120    for (i = 0; i < nv50->num_vtxbufs; ++i)
121       pipe_resource_reference(&nv50->vtxbuf[i].buffer, NULL);
122
123    pipe_resource_reference(&nv50->idxbuf.buffer, NULL);
124
125    for (s = 0; s < 3; ++s) {
126       assert(nv50->num_textures[s] <= PIPE_MAX_SAMPLERS);
127       for (i = 0; i < nv50->num_textures[s]; ++i)
128          pipe_sampler_view_reference(&nv50->textures[s][i], NULL);
129
130       for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i)
131          if (!nv50->constbuf[s][i].user)
132             pipe_resource_reference(&nv50->constbuf[s][i].u.buf, NULL);
133    }
134 }
135
136 static void
137 nv50_destroy(struct pipe_context *pipe)
138 {
139    struct nv50_context *nv50 = nv50_context(pipe);
140
141    if (nv50_context_screen(nv50)->cur_ctx == nv50)
142       nv50_context_screen(nv50)->cur_ctx = NULL;
143    nouveau_pushbuf_bufctx(nv50->base.pushbuf, NULL);
144    nouveau_pushbuf_kick(nv50->base.pushbuf, nv50->base.pushbuf->channel);
145
146    nv50_context_unreference_resources(nv50);
147
148    FREE(nv50->blit);
149
150    nouveau_context_destroy(&nv50->base);
151 }
152
153 static int
154 nv50_invalidate_resource_storage(struct nouveau_context *ctx,
155                                  struct pipe_resource *res,
156                                  int ref)
157 {
158    struct nv50_context *nv50 = nv50_context(&ctx->pipe);
159    unsigned s, i;
160
161    if (res->bind & PIPE_BIND_RENDER_TARGET) {
162       assert(nv50->framebuffer.nr_cbufs <= PIPE_MAX_COLOR_BUFS);
163       for (i = 0; i < nv50->framebuffer.nr_cbufs; ++i) {
164          if (nv50->framebuffer.cbufs[i] &&
165              nv50->framebuffer.cbufs[i]->texture == res) {
166             nv50->dirty |= NV50_NEW_FRAMEBUFFER;
167             nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_FB);
168             if (!--ref)
169                return ref;
170          }
171       }
172    }
173    if (res->bind & PIPE_BIND_DEPTH_STENCIL) {
174       if (nv50->framebuffer.zsbuf &&
175           nv50->framebuffer.zsbuf->texture == res) {
176          nv50->dirty |= NV50_NEW_FRAMEBUFFER;
177          nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_FB);
178          if (!--ref)
179             return ref;
180       }
181    }
182
183    if (res->bind & (PIPE_BIND_VERTEX_BUFFER |
184                     PIPE_BIND_INDEX_BUFFER |
185                     PIPE_BIND_CONSTANT_BUFFER |
186                     PIPE_BIND_STREAM_OUTPUT |
187                     PIPE_BIND_SAMPLER_VIEW)) {
188
189       assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
190       for (i = 0; i < nv50->num_vtxbufs; ++i) {
191          if (nv50->vtxbuf[i].buffer == res) {
192             nv50->dirty |= NV50_NEW_ARRAYS;
193             nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_VERTEX);
194             if (!--ref)
195                return ref;
196          }
197       }
198
199       if (nv50->idxbuf.buffer == res)
200          if (!--ref)
201             return ref;
202
203       for (s = 0; s < 3; ++s) {
204       assert(nv50->num_textures[s] <= PIPE_MAX_SAMPLERS);
205       for (i = 0; i < nv50->num_textures[s]; ++i) {
206          if (nv50->textures[s][i] &&
207              nv50->textures[s][i]->texture == res) {
208             nv50->dirty |= NV50_NEW_TEXTURES;
209             nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_TEXTURES);
210             if (!--ref)
211                return ref;
212          }
213       }
214       }
215
216       for (s = 0; s < 3; ++s) {
217       for (i = 0; i < NV50_MAX_PIPE_CONSTBUFS; ++i) {
218          if (!(nv50->constbuf_valid[s] & (1 << i)))
219             continue;
220          if (!nv50->constbuf[s][i].user &&
221              nv50->constbuf[s][i].u.buf == res) {
222             nv50->dirty |= NV50_NEW_CONSTBUF;
223             nv50->constbuf_dirty[s] |= 1 << i;
224             nouveau_bufctx_reset(nv50->bufctx_3d, NV50_BIND_CB(s, i));
225             if (!--ref)
226                return ref;
227          }
228       }
229       }
230    }
231
232    return ref;
233 }
234
235 static void
236 nv50_context_get_sample_position(struct pipe_context *, unsigned, unsigned,
237                                  float *);
238
239 struct pipe_context *
240 nv50_create(struct pipe_screen *pscreen, void *priv)
241 {
242    struct nv50_screen *screen = nv50_screen(pscreen);
243    struct nv50_context *nv50;
244    struct pipe_context *pipe;
245    int ret;
246    uint32_t flags;
247
248    nv50 = CALLOC_STRUCT(nv50_context);
249    if (!nv50)
250       return NULL;
251    pipe = &nv50->base.pipe;
252
253    if (!nv50_blitctx_create(nv50))
254       goto out_err;
255
256    nv50->base.pushbuf = screen->base.pushbuf;
257    nv50->base.client = screen->base.client;
258
259    ret = nouveau_bufctx_new(screen->base.client, NV50_BIND_COUNT,
260                             &nv50->bufctx_3d);
261    if (!ret)
262       ret = nouveau_bufctx_new(screen->base.client, 2, &nv50->bufctx);
263    if (ret)
264       goto out_err;
265
266    nv50->base.screen    = &screen->base;
267    nv50->base.copy_data = nv50_m2mf_copy_linear;
268    nv50->base.push_data = nv50_sifc_linear_u8;
269    /* FIXME: Make it possible to use this again. The problem is that there is
270     * some clever logic in the card that allows for multiple renders to happen
271     * when there are only constbuf changes. However that relies on the
272     * constbuf updates happening to the right constbuf slots. Currently
273     * implementation just makes it go through a separate slot which doesn't
274     * properly update the right constbuf data.
275    nv50->base.push_cb   = nv50_cb_push;
276     */
277
278    nv50->screen = screen;
279    pipe->screen = pscreen;
280    pipe->priv = priv;
281
282    pipe->destroy = nv50_destroy;
283
284    pipe->draw_vbo = nv50_draw_vbo;
285    pipe->clear = nv50_clear;
286
287    pipe->flush = nv50_flush;
288    pipe->texture_barrier = nv50_texture_barrier;
289    pipe->memory_barrier = nv50_memory_barrier;
290    pipe->get_sample_position = nv50_context_get_sample_position;
291
292    if (!screen->cur_ctx) {
293       screen->cur_ctx = nv50;
294       nouveau_pushbuf_bufctx(screen->base.pushbuf, nv50->bufctx);
295    }
296    nv50->base.pushbuf->kick_notify = nv50_default_kick_notify;
297
298    nv50_init_query_functions(nv50);
299    nv50_init_surface_functions(nv50);
300    nv50_init_state_functions(nv50);
301    nv50_init_resource_functions(pipe);
302
303    nv50->base.invalidate_resource_storage = nv50_invalidate_resource_storage;
304
305    if (screen->base.device->chipset < 0x84 ||
306        debug_get_bool_option("NOUVEAU_PMPEG", FALSE)) {
307       /* PMPEG */
308       nouveau_context_init_vdec(&nv50->base);
309    } else if (screen->base.device->chipset < 0x98 ||
310               screen->base.device->chipset == 0xa0) {
311       /* VP2 */
312       pipe->create_video_codec = nv84_create_decoder;
313       pipe->create_video_buffer = nv84_video_buffer_create;
314    } else {
315       /* VP3/4 */
316       pipe->create_video_codec = nv98_create_decoder;
317       pipe->create_video_buffer = nv98_video_buffer_create;
318    }
319
320    flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD;
321
322    BCTX_REFN_bo(nv50->bufctx_3d, SCREEN, flags, screen->code);
323    BCTX_REFN_bo(nv50->bufctx_3d, SCREEN, flags, screen->uniforms);
324    BCTX_REFN_bo(nv50->bufctx_3d, SCREEN, flags, screen->txc);
325    BCTX_REFN_bo(nv50->bufctx_3d, SCREEN, flags, screen->stack_bo);
326
327    flags = NOUVEAU_BO_GART | NOUVEAU_BO_WR;
328
329    BCTX_REFN_bo(nv50->bufctx_3d, SCREEN, flags, screen->fence.bo);
330    BCTX_REFN_bo(nv50->bufctx, FENCE, flags, screen->fence.bo);
331
332    nv50->base.scratch.bo_size = 2 << 20;
333
334    return pipe;
335
336 out_err:
337    if (nv50->bufctx_3d)
338       nouveau_bufctx_del(&nv50->bufctx_3d);
339    if (nv50->bufctx)
340       nouveau_bufctx_del(&nv50->bufctx);
341    if (nv50->blit)
342       FREE(nv50->blit);
343    FREE(nv50);
344    return NULL;
345 }
346
347 void
348 nv50_bufctx_fence(struct nouveau_bufctx *bufctx, boolean on_flush)
349 {
350    struct nouveau_list *list = on_flush ? &bufctx->current : &bufctx->pending;
351    struct nouveau_list *it;
352
353    for (it = list->next; it != list; it = it->next) {
354       struct nouveau_bufref *ref = (struct nouveau_bufref *)it;
355       struct nv04_resource *res = ref->priv;
356       if (res)
357          nv50_resource_validate(res, (unsigned)ref->priv_data);
358    }
359 }
360
361 static void
362 nv50_context_get_sample_position(struct pipe_context *pipe,
363                                  unsigned sample_count, unsigned sample_index,
364                                  float *xy)
365 {
366    static const uint8_t ms1[1][2] = { { 0x8, 0x8 } };
367    static const uint8_t ms2[2][2] = {
368       { 0x4, 0x4 }, { 0xc, 0xc } }; /* surface coords (0,0), (1,0) */
369    static const uint8_t ms4[4][2] = {
370       { 0x6, 0x2 }, { 0xe, 0x6 },   /* (0,0), (1,0) */
371       { 0x2, 0xa }, { 0xa, 0xe } }; /* (0,1), (1,1) */
372    static const uint8_t ms8[8][2] = {
373       { 0x1, 0x7 }, { 0x5, 0x3 },   /* (0,0), (1,0) */
374       { 0x3, 0xd }, { 0x7, 0xb },   /* (0,1), (1,1) */
375       { 0x9, 0x5 }, { 0xf, 0x1 },   /* (2,0), (3,0) */
376       { 0xb, 0xf }, { 0xd, 0x9 } }; /* (2,1), (3,1) */
377 #if 0
378    /* NOTE: there are alternative modes for MS2 and MS8, currently not used */
379    static const uint8_t ms8_alt[8][2] = {
380       { 0x9, 0x5 }, { 0x7, 0xb },   /* (2,0), (1,1) */
381       { 0xd, 0x9 }, { 0x5, 0x3 },   /* (3,1), (1,0) */
382       { 0x3, 0xd }, { 0x1, 0x7 },   /* (0,1), (0,0) */
383       { 0xb, 0xf }, { 0xf, 0x1 } }; /* (2,1), (3,0) */
384 #endif
385
386    const uint8_t (*ptr)[2];
387
388    switch (sample_count) {
389    case 0:
390    case 1: ptr = ms1; break;
391    case 2: ptr = ms2; break;
392    case 4: ptr = ms4; break;
393    case 8: ptr = ms8; break;
394    default:
395       assert(0);
396       return; /* bad sample count -> undefined locations */
397    }
398    xy[0] = ptr[sample_index][0] * 0.0625f;
399    xy[1] = ptr[sample_index][1] * 0.0625f;
400 }