Merge remote branch 'upstream/gallium-0.2' into nouveau-gallium-0.2
[mesa.git] / src / gallium / winsys / drm / 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;
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 if (nv_screen->front_cpp == 2)
171 fb_surf->format = PIPE_FORMAT_R5G6B5_UNORM;
172 else
173 fb_surf->format = PIPE_FORMAT_A8R8G8B8_UNORM;
174 pf_get_block(fb_surf->format, &fb_surf->block);
175 fb_surf->width = nv_screen->front_pitch / nv_screen->front_cpp;
176 fb_surf->height = nv_screen->front_height;
177 fb_surf->stride = fb_surf->width * fb_surf->block.size;
178 fb_surf->refcount = 1;
179 fb_surf->buffer = &fb_buf->base;
180
181 nv->frontbuffer = fb_surf;
182 }
183
184 /* Attempt to share a single channel between multiple contexts from
185 * a single process.
186 */
187 nvc = nv_screen->nvc;
188 if (!nvc && st_share) {
189 struct nouveau_context *snv = st_share->pipe->priv;
190 if (snv) {
191 nvc = snv->nvc;
192 }
193 }
194
195 /*XXX: temporary - disable multi-context/single-channel on pre-NV4x */
196 switch (dev->chipset & 0xf0) {
197 case 0x40:
198 case 0x60:
199 /* NV40 class */
200 case 0x50:
201 case 0x80:
202 case 0x90:
203 /* G80 class */
204 break;
205 default:
206 nvc = NULL;
207 break;
208 }
209
210 if (!nvc) {
211 nvc = nouveau_channel_context_create(dev);
212 if (!nvc) {
213 NOUVEAU_ERR("Failed initialising GPU context\n");
214 return GL_FALSE;
215 }
216 nv_screen->nvc = nvc;
217 }
218
219 nvc->refcount++;
220 nv->nvc = nvc;
221
222 /* Find a free slot for a pipe context, allocate a new one if needed */
223 nv->pctx_id = -1;
224 for (i = 0; i < nvc->nr_pctx; i++) {
225 if (nvc->pctx[i] == NULL) {
226 nv->pctx_id = i;
227 break;
228 }
229 }
230
231 if (nv->pctx_id < 0) {
232 nv->pctx_id = nvc->nr_pctx++;
233 nvc->pctx =
234 realloc(nvc->pctx,
235 sizeof(struct pipe_context *) * nvc->nr_pctx);
236 }
237
238 /* Create pipe */
239 switch (dev->chipset & 0xf0) {
240 case 0x50:
241 case 0x80:
242 case 0x90:
243 if (nouveau_surface_init_nv50(nv))
244 return GL_FALSE;
245 break;
246 default:
247 if (nouveau_surface_init_nv04(nv))
248 return GL_FALSE;
249 break;
250 }
251
252 if (!getenv("NOUVEAU_FORCE_SOFTPIPE")) {
253 struct pipe_screen *pscreen;
254
255 pipe = nouveau_pipe_create(nv);
256 if (!pipe)
257 NOUVEAU_ERR("Couldn't create hw pipe\n");
258 pscreen = nvc->pscreen;
259
260 nv->cap.hw_vertex_buffer =
261 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_VTXBUF);
262 nv->cap.hw_index_buffer =
263 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF);
264 }
265
266 if (!pipe) {
267 NOUVEAU_MSG("Using softpipe\n");
268 pipe = nouveau_create_softpipe(nv);
269 if (!pipe) {
270 NOUVEAU_ERR("Error creating pipe, bailing\n");
271 return GL_FALSE;
272 }
273 }
274
275 pipe->priv = nv;
276 nv->st = st_create_context(pipe, glVis, st_share);
277 return GL_TRUE;
278 }
279
280 void
281 nouveau_context_destroy(__DRIcontextPrivate *driContextPriv)
282 {
283 struct nouveau_context *nv = driContextPriv->driverPrivate;
284 struct nouveau_channel_context *nvc = nv->nvc;
285
286 assert(nv);
287
288 st_finish(nv->st);
289 st_destroy_context(nv->st);
290
291 if (nv->pctx_id >= 0) {
292 nvc->pctx[nv->pctx_id] = NULL;
293 if (--nvc->refcount <= 0) {
294 nouveau_channel_context_destroy(nvc);
295 nv->nv_screen->nvc = NULL;
296 }
297 }
298
299 free(nv);
300 }
301
302 GLboolean
303 nouveau_context_bind(__DRIcontextPrivate *driContextPriv,
304 __DRIdrawablePrivate *driDrawPriv,
305 __DRIdrawablePrivate *driReadPriv)
306 {
307 struct nouveau_context *nv;
308 struct nouveau_framebuffer *draw, *read;
309
310 if (!driContextPriv) {
311 st_make_current(NULL, NULL, NULL);
312 return GL_TRUE;
313 }
314
315 nv = driContextPriv->driverPrivate;
316 draw = driDrawPriv->driverPrivate;
317 read = driReadPriv->driverPrivate;
318
319 st_make_current(nv->st, draw->stfb, read->stfb);
320
321 if ((nv->dri_drawable != driDrawPriv) ||
322 (nv->last_stamp != driDrawPriv->lastStamp)) {
323 nv->dri_drawable = driDrawPriv;
324 st_resize_framebuffer(draw->stfb, driDrawPriv->w,
325 driDrawPriv->h);
326 nv->last_stamp = driDrawPriv->lastStamp;
327 }
328
329 if (driDrawPriv != driReadPriv) {
330 st_resize_framebuffer(read->stfb, driReadPriv->w,
331 driReadPriv->h);
332 }
333
334 return GL_TRUE;
335 }
336
337 GLboolean
338 nouveau_context_unbind(__DRIcontextPrivate *driContextPriv)
339 {
340 struct nouveau_context *nv = driContextPriv->driverPrivate;
341 (void)nv;
342
343 st_flush(nv->st, 0, NULL);
344 return GL_TRUE;
345 }
346