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