1 /*
2  * Copyright 2012 Red Hat Inc.
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  * Authors: Ben Skeggs
23  *
24  */
25 
26 #include "draw/draw_context.h"
27 
28 #include "nv_object.xml.h"
29 #include "nv30/nv30-40_3d.xml.h"
30 
31 #include "nouveau_fence.h"
32 #include "nv30/nv30_context.h"
33 #include "nv30/nv30_transfer.h"
34 #include "nv30/nv30_state.h"
35 
36 static void
nv30_context_kick_notify(struct nouveau_pushbuf * push)37 nv30_context_kick_notify(struct nouveau_pushbuf *push)
38 {
39    struct nouveau_screen *screen;
40    struct nv30_context *nv30;
41 
42    if (!push->user_priv)
43       return;
44    nv30 = container_of(push->user_priv, nv30, bufctx);
45    screen = &nv30->screen->base;
46 
47    nouveau_fence_next(screen);
48    nouveau_fence_update(screen, true);
49 
50    if (push->bufctx) {
51       struct nouveau_bufref *bref;
52       LIST_FOR_EACH_ENTRY(bref, &push->bufctx->current, thead) {
53          struct nv04_resource *res = bref->priv;
54          if (res && res->mm) {
55             nouveau_fence_ref(screen->fence.current, &res->fence);
56 
57             if (bref->flags & NOUVEAU_BO_RD)
58                res->status |= NOUVEAU_BUFFER_STATUS_GPU_READING;
59 
60             if (bref->flags & NOUVEAU_BO_WR) {
61                nouveau_fence_ref(screen->fence.current, &res->fence_wr);
62                res->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING |
63                   NOUVEAU_BUFFER_STATUS_DIRTY;
64             }
65          }
66       }
67    }
68 }
69 
70 static void
nv30_context_flush(struct pipe_context * pipe,struct pipe_fence_handle ** fence,unsigned flags)71 nv30_context_flush(struct pipe_context *pipe, struct pipe_fence_handle **fence,
72                    unsigned flags)
73 {
74    struct nv30_context *nv30 = nv30_context(pipe);
75    struct nouveau_pushbuf *push = nv30->base.pushbuf;
76 
77    if (fence)
78       nouveau_fence_ref(nv30->screen->base.fence.current,
79                         (struct nouveau_fence **)fence);
80 
81    PUSH_KICK(push);
82 
83    nouveau_context_update_frame_stats(&nv30->base);
84 }
85 
86 static int
nv30_invalidate_resource_storage(struct nouveau_context * nv,struct pipe_resource * res,int ref)87 nv30_invalidate_resource_storage(struct nouveau_context *nv,
88                                  struct pipe_resource *res,
89                                  int ref)
90 {
91    struct nv30_context *nv30 = nv30_context(&nv->pipe);
92    unsigned i;
93 
94    if (res->bind & PIPE_BIND_RENDER_TARGET) {
95       for (i = 0; i < nv30->framebuffer.nr_cbufs; ++i) {
96          if (nv30->framebuffer.cbufs[i] &&
97              nv30->framebuffer.cbufs[i]->texture == res) {
98             nv30->dirty |= NV30_NEW_FRAMEBUFFER;
99             nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FB);
100             if (!--ref)
101                return ref;
102          }
103       }
104    }
105    if (res->bind & PIPE_BIND_DEPTH_STENCIL) {
106       if (nv30->framebuffer.zsbuf &&
107           nv30->framebuffer.zsbuf->texture == res) {
108             nv30->dirty |= NV30_NEW_FRAMEBUFFER;
109             nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FB);
110             if (!--ref)
111                return ref;
112       }
113    }
114 
115    if (res->bind & PIPE_BIND_VERTEX_BUFFER) {
116       for (i = 0; i < nv30->num_vtxbufs; ++i) {
117          if (nv30->vtxbuf[i].buffer == res) {
118             nv30->dirty |= NV30_NEW_ARRAYS;
119             nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VTXBUF);
120             if (!--ref)
121                return ref;
122          }
123       }
124    }
125    if (res->bind & PIPE_BIND_INDEX_BUFFER) {
126       if (nv30->idxbuf.buffer == res) {
127          nouveau_bufctx_reset(nv30->bufctx, BUFCTX_IDXBUF);
128          if (!--ref)
129             return ref;
130       }
131    }
132 
133    if (res->bind & PIPE_BIND_SAMPLER_VIEW) {
134       for (i = 0; i < nv30->fragprog.num_textures; ++i) {
135          if (nv30->fragprog.textures[i] &&
136              nv30->fragprog.textures[i]->texture == res) {
137             nv30->dirty |= NV30_NEW_FRAGTEX;
138             nouveau_bufctx_reset(nv30->bufctx, BUFCTX_FRAGTEX(i));
139             if (!--ref)
140                return ref;
141          }
142       }
143       for (i = 0; i < nv30->vertprog.num_textures; ++i) {
144          if (nv30->vertprog.textures[i] &&
145              nv30->vertprog.textures[i]->texture == res) {
146             nv30->dirty |= NV30_NEW_VERTTEX;
147             nouveau_bufctx_reset(nv30->bufctx, BUFCTX_VERTTEX(i));
148             if (!--ref)
149                return ref;
150          }
151       }
152    }
153 
154    return ref;
155 }
156 
157 static void
nv30_context_destroy(struct pipe_context * pipe)158 nv30_context_destroy(struct pipe_context *pipe)
159 {
160    struct nv30_context *nv30 = nv30_context(pipe);
161 
162    if (nv30->blitter)
163       util_blitter_destroy(nv30->blitter);
164 
165    if (nv30->draw)
166       draw_destroy(nv30->draw);
167 
168    if (nv30->blit_vp)
169       nouveau_heap_free(&nv30->blit_vp);
170 
171    if (nv30->blit_fp)
172       pipe_resource_reference(&nv30->blit_fp, NULL);
173 
174    if (nv30->screen->base.pushbuf->user_priv == &nv30->bufctx)
175       nv30->screen->base.pushbuf->user_priv = NULL;
176 
177    nouveau_bufctx_del(&nv30->bufctx);
178 
179    if (nv30->screen->cur_ctx == nv30)
180       nv30->screen->cur_ctx = NULL;
181 
182    nouveau_context_destroy(&nv30->base);
183 }
184 
185 #define FAIL_CONTEXT_INIT(str, err)                   \
186    do {                                               \
187       NOUVEAU_ERR(str, err);                          \
188       nv30_context_destroy(pipe);                     \
189       return NULL;                                    \
190    } while(0)
191 
192 struct pipe_context *
nv30_context_create(struct pipe_screen * pscreen,void * priv,unsigned ctxflags)193 nv30_context_create(struct pipe_screen *pscreen, void *priv, unsigned ctxflags)
194 {
195    struct nv30_screen *screen = nv30_screen(pscreen);
196    struct nv30_context *nv30 = CALLOC_STRUCT(nv30_context);
197    struct nouveau_pushbuf *push;
198    struct pipe_context *pipe;
199    int ret;
200 
201    if (!nv30)
202       return NULL;
203 
204    nv30->screen = screen;
205    nv30->base.screen = &screen->base;
206    nv30->base.copy_data = nv30_transfer_copy_data;
207 
208    pipe = &nv30->base.pipe;
209    pipe->screen = pscreen;
210    pipe->priv = priv;
211    pipe->destroy = nv30_context_destroy;
212    pipe->flush = nv30_context_flush;
213 
214    /*XXX: *cough* per-context client */
215    nv30->base.client = screen->base.client;
216 
217    /*XXX: *cough* per-context pushbufs */
218    push = screen->base.pushbuf;
219    nv30->base.pushbuf = push;
220    nv30->base.pushbuf->user_priv = &nv30->bufctx; /* hack at validate time */
221    nv30->base.pushbuf->rsvd_kick = 16; /* hack in screen before first space */
222    nv30->base.pushbuf->kick_notify = nv30_context_kick_notify;
223 
224    nv30->base.invalidate_resource_storage = nv30_invalidate_resource_storage;
225 
226    ret = nouveau_bufctx_new(nv30->base.client, 64, &nv30->bufctx);
227    if (ret) {
228       nv30_context_destroy(pipe);
229       return NULL;
230    }
231 
232    /*XXX: make configurable with performance vs quality, these defaults
233     *     match the binary driver's defaults
234     */
235    if (screen->eng3d->oclass < NV40_3D_CLASS)
236       nv30->config.filter = 0x00000004;
237    else
238       nv30->config.filter = 0x00002dc4;
239 
240    nv30->config.aniso = NV40_3D_TEX_WRAP_ANISO_MIP_FILTER_OPTIMIZATION_OFF;
241 
242    if (debug_get_bool_option("NV30_SWTNL", false))
243       nv30->draw_flags |= NV30_NEW_SWTNL;
244 
245    nouveau_context_init(&nv30->base);
246    nv30->sample_mask = 0xffff;
247    nv30_vbo_init(pipe);
248    nv30_query_init(pipe);
249    nv30_state_init(pipe);
250    nv30_resource_init(pipe);
251    nv30_clear_init(pipe);
252    nv30_fragprog_init(pipe);
253    nv30_vertprog_init(pipe);
254    nv30_texture_init(pipe);
255    nv30_fragtex_init(pipe);
256    nv40_verttex_init(pipe);
257    nv30_draw_init(pipe);
258 
259    nv30->blitter = util_blitter_create(pipe);
260    if (!nv30->blitter) {
261       nv30_context_destroy(pipe);
262       return NULL;
263    }
264 
265    nouveau_context_init_vdec(&nv30->base);
266 
267    return pipe;
268 }
269