Merge remote branch 'upstream/gallium-0.1' into nouveau-gallium-0.1
[mesa.git] / src / gallium / winsys / dri / nouveau / nouveau_context.c
1 #include "main/glheader.h"
2 #include "glapi/glthread.h"
3 #include <GL/internal/glcore.h>
4 #include "utils.h"
5
6 #include "state_tracker/st_public.h"
7 #include "state_tracker/st_context.h"
8 #include "pipe/p_defines.h"
9 #include "pipe/p_context.h"
10 #include "pipe/p_screen.h"
11
12 #include "nouveau_context.h"
13 #include "nouveau_dri.h"
14 #include "nouveau_local.h"
15 #include "nouveau_screen.h"
16 #include "nouveau_winsys_pipe.h"
17
18 #ifdef DEBUG
19 static const struct dri_debug_control debug_control[] = {
20 { "bo", DEBUG_BO },
21 { NULL, 0 }
22 };
23 int __nouveau_debug = 0;
24 #endif
25
26 static void
27 nouveau_channel_context_destroy(struct nouveau_channel_context *nvc)
28 {
29 nouveau_grobj_free(&nvc->NvCtxSurf2D);
30 nouveau_grobj_free(&nvc->NvImageBlit);
31 nouveau_grobj_free(&nvc->NvGdiRect);
32 nouveau_grobj_free(&nvc->NvM2MF);
33 nouveau_grobj_free(&nvc->Nv2D);
34 nouveau_grobj_free(&nvc->NvSwzSurf);
35 nouveau_grobj_free(&nvc->NvSIFM);
36
37 nouveau_notifier_free(&nvc->sync_notifier);
38
39 nouveau_channel_free(&nvc->channel);
40
41 FREE(nvc);
42 }
43
44 static struct nouveau_channel_context *
45 nouveau_channel_context_create(struct nouveau_device *dev)
46 {
47 struct nouveau_channel_context *nvc;
48 int ret;
49
50 nvc = CALLOC_STRUCT(nouveau_channel_context);
51 if (!nvc)
52 return NULL;
53
54 if ((ret = nouveau_channel_alloc(dev, 0x8003d001, 0x8003d002,
55 &nvc->channel))) {
56 NOUVEAU_ERR("Error creating GPU channel: %d\n", ret);
57 nouveau_channel_context_destroy(nvc);
58 return NULL;
59 }
60
61 nvc->next_handle = 0x80000000;
62
63 if ((ret = nouveau_notifier_alloc(nvc->channel, nvc->next_handle++, 1,
64 &nvc->sync_notifier))) {
65 NOUVEAU_ERR("Error creating channel sync notifier: %d\n", ret);
66 nouveau_channel_context_destroy(nvc);
67 return NULL;
68 }
69
70 switch (dev->chipset & 0xf0) {
71 case 0x50:
72 case 0x80:
73 case 0x90:
74 ret = nouveau_surface_channel_create_nv50(nvc);
75 break;
76 default:
77 ret = nouveau_surface_channel_create_nv04(nvc);
78 break;
79 }
80
81 if (ret) {
82 NOUVEAU_ERR("Error initialising surface objects: %d\n", ret);
83 nouveau_channel_context_destroy(nvc);
84 return NULL;
85 }
86
87 return nvc;
88 }
89
90 GLboolean
91 nouveau_context_create(const __GLcontextModes *glVis,
92 __DRIcontextPrivate *driContextPriv,
93 void *sharedContextPrivate)
94 {
95 __DRIscreenPrivate *driScrnPriv = driContextPriv->driScreenPriv;
96 struct nouveau_screen *nv_screen = driScrnPriv->private;
97 struct nouveau_context *nv = CALLOC_STRUCT(nouveau_context);
98 struct pipe_context *pipe = NULL;
99 struct st_context *st_share = NULL;
100 struct nouveau_channel_context *nvc = NULL;
101 struct nouveau_device *dev = nv_screen->device;
102 int i, ret;
103
104 if (sharedContextPrivate) {
105 st_share = ((struct nouveau_context *)sharedContextPrivate)->st;
106 }
107
108 switch (dev->chipset & 0xf0) {
109 case 0x10:
110 case 0x20:
111 /* NV10 */
112 case 0x30:
113 /* NV30 */
114 case 0x40:
115 case 0x60:
116 /* NV40 */
117 case 0x50:
118 case 0x80:
119 case 0x90:
120 /* G80 */
121 break;
122 default:
123 NOUVEAU_ERR("Unsupported chipset: NV%02x\n", dev->chipset);
124 return GL_FALSE;
125 }
126
127 driContextPriv->driverPrivate = (void *)nv;
128 nv->nv_screen = nv_screen;
129 nv->dri_screen = driScrnPriv;
130
131 {
132 struct nouveau_device_priv *nvdev = nouveau_device(dev);
133
134 nvdev->ctx = driContextPriv->hHWContext;
135 nvdev->lock = (drmLock *)&driScrnPriv->pSAREA->lock;
136 }
137
138 driParseConfigFiles(&nv->dri_option_cache, &nv_screen->option_cache,
139 nv->dri_screen->myNum, "nouveau");
140 #ifdef DEBUG
141 __nouveau_debug = driParseDebugString(getenv("NOUVEAU_DEBUG"),
142 debug_control);
143 #endif
144
145 /*XXX: Hack up a fake region and buffer object for front buffer.
146 * This will go away with TTM, replaced with a simple reference
147 * of the front buffer handle passed to us by the DDX.
148 */
149 {
150 struct pipe_surface *fb_surf;
151 struct nouveau_pipe_buffer *fb_buf;
152 struct nouveau_bo_priv *fb_bo;
153
154 fb_bo = calloc(1, sizeof(struct nouveau_bo_priv));
155 fb_bo->drm.offset = nv_screen->front_offset;
156 fb_bo->drm.flags = NOUVEAU_MEM_FB;
157 fb_bo->drm.size = nv_screen->front_pitch *
158 nv_screen->front_height;
159 fb_bo->refcount = 1;
160 fb_bo->base.flags = NOUVEAU_BO_PIN | NOUVEAU_BO_VRAM;
161 fb_bo->base.offset = fb_bo->drm.offset;
162 fb_bo->base.handle = (unsigned long)fb_bo;
163 fb_bo->base.size = fb_bo->drm.size;
164 fb_bo->base.device = nv_screen->device;
165
166 fb_buf = calloc(1, sizeof(struct nouveau_pipe_buffer));
167 fb_buf->bo = &fb_bo->base;
168
169 fb_surf = calloc(1, sizeof(struct pipe_surface));
170 fb_surf->cpp = nv_screen->front_cpp;
171 fb_surf->pitch = nv_screen->front_pitch / fb_surf->cpp;
172 fb_surf->height = nv_screen->front_height;
173 fb_surf->refcount = 1;
174 fb_surf->buffer = &fb_buf->base;
175
176 nv->frontbuffer = fb_surf;
177 }
178
179 /* Attempt to share a single channel between multiple contexts from
180 * a single process.
181 */
182 nvc = nv_screen->nvc;
183 if (!nvc && st_share) {
184 struct nouveau_context *snv = st_share->pipe->priv;
185 if (snv) {
186 nvc = snv->nvc;
187 }
188 }
189
190 /*XXX: temporary - disable multi-context/single-channel on pre-NV4x */
191 switch (dev->chipset & 0xf0) {
192 case 0x40:
193 case 0x60:
194 /* NV40 class */
195 case 0x50:
196 case 0x80:
197 case 0x90:
198 /* G80 class */
199 break;
200 default:
201 nvc = NULL;
202 break;
203 }
204
205 if (!nvc) {
206 nvc = nouveau_channel_context_create(dev);
207 if (!nvc) {
208 NOUVEAU_ERR("Failed initialising GPU context\n");
209 return GL_FALSE;
210 }
211 nv_screen->nvc = nvc;
212 }
213
214 nvc->refcount++;
215 nv->nvc = nvc;
216
217 /* Find a free slot for a pipe context, allocate a new one if needed */
218 nv->pctx_id = -1;
219 for (i = 0; i < nvc->nr_pctx; i++) {
220 if (nvc->pctx[i] == NULL) {
221 nv->pctx_id = i;
222 break;
223 }
224 }
225
226 if (nv->pctx_id < 0) {
227 nv->pctx_id = nvc->nr_pctx++;
228 nvc->pctx =
229 realloc(nvc->pctx,
230 sizeof(struct pipe_context *) * nvc->nr_pctx);
231 }
232
233 /* Create pipe */
234 switch (dev->chipset & 0xf0) {
235 case 0x50:
236 case 0x80:
237 case 0x90:
238 if (nouveau_surface_init_nv50(nv))
239 return GL_FALSE;
240 break;
241 default:
242 if (nouveau_surface_init_nv04(nv))
243 return GL_FALSE;
244 break;
245 }
246
247 if (!getenv("NOUVEAU_FORCE_SOFTPIPE")) {
248 struct pipe_screen *pscreen;
249
250 pipe = nouveau_pipe_create(nv);
251 if (!pipe)
252 NOUVEAU_ERR("Couldn't create hw pipe\n");
253 pscreen = nvc->pscreen;
254
255 nv->cap.hw_vertex_buffer =
256 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_VTXBUF);
257 nv->cap.hw_index_buffer =
258 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF);
259 }
260
261 if (!pipe) {
262 NOUVEAU_MSG("Using softpipe\n");
263 pipe = nouveau_create_softpipe(nv);
264 if (!pipe) {
265 NOUVEAU_ERR("Error creating pipe, bailing\n");
266 return GL_FALSE;
267 }
268 }
269
270 pipe->priv = nv;
271 nv->st = st_create_context(pipe, glVis, st_share);
272 return GL_TRUE;
273 }
274
275 void
276 nouveau_context_destroy(__DRIcontextPrivate *driContextPriv)
277 {
278 struct nouveau_context *nv = driContextPriv->driverPrivate;
279 struct nouveau_channel_context *nvc = nv->nvc;
280
281 assert(nv);
282
283 st_finish(nv->st);
284 st_destroy_context(nv->st);
285
286 if (nv->pctx_id >= 0) {
287 nvc->pctx[nv->pctx_id] = NULL;
288 if (--nvc->refcount <= 0) {
289 nouveau_channel_context_destroy(nvc);
290 nv->nv_screen->nvc = NULL;
291 }
292 }
293
294 free(nv);
295 }
296
297 GLboolean
298 nouveau_context_bind(__DRIcontextPrivate *driContextPriv,
299 __DRIdrawablePrivate *driDrawPriv,
300 __DRIdrawablePrivate *driReadPriv)
301 {
302 struct nouveau_context *nv;
303 struct nouveau_framebuffer *draw, *read;
304
305 if (!driContextPriv) {
306 st_make_current(NULL, NULL, NULL);
307 return GL_TRUE;
308 }
309
310 nv = driContextPriv->driverPrivate;
311 draw = driDrawPriv->driverPrivate;
312 read = driReadPriv->driverPrivate;
313
314 st_make_current(nv->st, draw->stfb, read->stfb);
315
316 if ((nv->dri_drawable != driDrawPriv) ||
317 (nv->last_stamp != driDrawPriv->lastStamp)) {
318 nv->dri_drawable = driDrawPriv;
319 st_resize_framebuffer(draw->stfb, driDrawPriv->w,
320 driDrawPriv->h);
321 nv->last_stamp = driDrawPriv->lastStamp;
322 }
323
324 if (driDrawPriv != driReadPriv) {
325 st_resize_framebuffer(read->stfb, driReadPriv->w,
326 driReadPriv->h);
327 }
328
329 return GL_TRUE;
330 }
331
332 GLboolean
333 nouveau_context_unbind(__DRIcontextPrivate *driContextPriv)
334 {
335 struct nouveau_context *nv = driContextPriv->driverPrivate;
336 (void)nv;
337
338 st_flush(nv->st, 0, NULL);
339 return GL_TRUE;
340 }
341