g3dvl: Add Nouveau winsys, libdriclient.
[mesa.git] / src / gallium / winsys / g3dvl / nouveau / nouveau_context.c
1 #include "pipe/p_defines.h"
2 #include "pipe/p_context.h"
3 #include "pipe/p_screen.h"
4 #include "pipe/p_util.h"
5
6 #include "nouveau_context.h"
7 #include "nouveau_dri.h"
8 #include "nouveau_local.h"
9 #include "nouveau_screen.h"
10 #include "nouveau_winsys_pipe.h"
11
12 /*
13 #ifdef DEBUG
14 static const struct dri_debug_control debug_control[] = {
15 { "bo", DEBUG_BO },
16 { NULL, 0 }
17 };
18 int __nouveau_debug = 0;
19 #endif
20 */
21
22 /*
23 * TODO: Re-examine dri_screen, dri_context, nouveau_screen, nouveau_context
24 * relationships, seems like there is a lot of room for simplification there.
25 */
26
27 static void
28 nouveau_channel_context_destroy(struct nouveau_channel_context *nvc)
29 {
30 nouveau_grobj_free(&nvc->NvCtxSurf2D);
31 nouveau_grobj_free(&nvc->NvImageBlit);
32 nouveau_grobj_free(&nvc->NvGdiRect);
33 nouveau_grobj_free(&nvc->NvM2MF);
34 nouveau_grobj_free(&nvc->Nv2D);
35 nouveau_grobj_free(&nvc->NvSwzSurf);
36 nouveau_grobj_free(&nvc->NvSIFM);
37
38 nouveau_notifier_free(&nvc->sync_notifier);
39
40 nouveau_channel_free(&nvc->channel);
41
42 FREE(nvc);
43 }
44
45 static struct nouveau_channel_context *
46 nouveau_channel_context_create(struct nouveau_device *dev)
47 {
48 struct nouveau_channel_context *nvc;
49 int ret;
50
51 nvc = CALLOC_STRUCT(nouveau_channel_context);
52 if (!nvc)
53 return NULL;
54
55 if ((ret = nouveau_channel_alloc(dev, 0x8003d001, 0x8003d002,
56 &nvc->channel))) {
57 NOUVEAU_ERR("Error creating GPU channel: %d\n", ret);
58 nouveau_channel_context_destroy(nvc);
59 return NULL;
60 }
61
62 nvc->next_handle = 0x80000000;
63
64 if ((ret = nouveau_notifier_alloc(nvc->channel, nvc->next_handle++, 1,
65 &nvc->sync_notifier))) {
66 NOUVEAU_ERR("Error creating channel sync notifier: %d\n", ret);
67 nouveau_channel_context_destroy(nvc);
68 return NULL;
69 }
70
71 switch (dev->chipset & 0xf0) {
72 case 0x50:
73 case 0x80:
74 case 0x90:
75 ret = nouveau_surface_channel_create_nv50(nvc);
76 break;
77 default:
78 ret = nouveau_surface_channel_create_nv04(nvc);
79 break;
80 }
81
82 if (ret) {
83 NOUVEAU_ERR("Error initialising surface objects: %d\n", ret);
84 nouveau_channel_context_destroy(nvc);
85 return NULL;
86 }
87
88 return nvc;
89 }
90
91 int
92 nouveau_context_create(dri_context_t *dri_context)
93 {
94 dri_screen_t *dri_screen = dri_context->dri_screen;
95 struct nouveau_screen *nv_screen = dri_screen->private;
96 struct nouveau_context *nv = CALLOC_STRUCT(nouveau_context);
97 struct pipe_context *pipe = NULL;
98 struct nouveau_channel_context *nvc = NULL;
99 struct nouveau_device *dev = nv_screen->device;
100 int i;
101
102 switch (dev->chipset & 0xf0) {
103 case 0x10:
104 case 0x20:
105 /* NV10 */
106 case 0x30:
107 /* NV30 */
108 case 0x40:
109 case 0x60:
110 /* NV40 */
111 case 0x50:
112 case 0x80:
113 case 0x90:
114 /* G80 */
115 break;
116 default:
117 NOUVEAU_ERR("Unsupported chipset: NV%02x\n", dev->chipset);
118 return 1;
119 }
120
121 dri_context->private = (void*)nv;
122 nv->dri_context = dri_context;
123 nv->nv_screen = nv_screen;
124
125 {
126 struct nouveau_device_priv *nvdev = nouveau_device(dev);
127
128 nvdev->ctx = dri_context->drm_context;
129 nvdev->lock = (drmLock*)&dri_screen->sarea->lock;
130 }
131
132 /*
133 driParseConfigFiles(&nv->dri_option_cache, &nv_screen->option_cache,
134 nv->dri_screen->myNum, "nouveau");
135 #ifdef DEBUG
136 __nouveau_debug = driParseDebugString(getenv("NOUVEAU_DEBUG"),
137 debug_control);
138 #endif
139 */
140
141 /*XXX: Hack up a fake region and buffer object for front buffer.
142 * This will go away with TTM, replaced with a simple reference
143 * of the front buffer handle passed to us by the DDX.
144 */
145 {
146 struct pipe_surface *fb_surf;
147 struct nouveau_pipe_buffer *fb_buf;
148 struct nouveau_bo_priv *fb_bo;
149
150 fb_bo = calloc(1, sizeof(struct nouveau_bo_priv));
151 fb_bo->drm.offset = nv_screen->front_offset;
152 fb_bo->drm.flags = NOUVEAU_MEM_FB;
153 fb_bo->drm.size = nv_screen->front_pitch *
154 nv_screen->front_height;
155 fb_bo->refcount = 1;
156 fb_bo->base.flags = NOUVEAU_BO_PIN | NOUVEAU_BO_VRAM;
157 fb_bo->base.offset = fb_bo->drm.offset;
158 fb_bo->base.handle = (unsigned long)fb_bo;
159 fb_bo->base.size = fb_bo->drm.size;
160 fb_bo->base.device = nv_screen->device;
161
162 fb_buf = calloc(1, sizeof(struct nouveau_pipe_buffer));
163 fb_buf->bo = &fb_bo->base;
164
165 fb_surf = calloc(1, sizeof(struct pipe_surface));
166 if (nv_screen->front_cpp == 2)
167 fb_surf->format = PIPE_FORMAT_R5G6B5_UNORM;
168 else
169 fb_surf->format = PIPE_FORMAT_A8R8G8B8_UNORM;
170 pf_get_block(fb_surf->format, &fb_surf->block);
171 fb_surf->width = nv_screen->front_pitch / nv_screen->front_cpp;
172 fb_surf->height = nv_screen->front_height;
173 fb_surf->stride = fb_surf->width * fb_surf->block.size;
174 fb_surf->refcount = 1;
175 fb_surf->buffer = &fb_buf->base;
176
177 nv->frontbuffer = fb_surf;
178 }
179
180 nvc = nv_screen->nvc;
181
182 if (!nvc) {
183 nvc = nouveau_channel_context_create(dev);
184 if (!nvc) {
185 NOUVEAU_ERR("Failed initialising GPU context\n");
186 return 1;
187 }
188 nv_screen->nvc = nvc;
189 }
190
191 nvc->refcount++;
192 nv->nvc = nvc;
193
194 /* Find a free slot for a pipe context, allocate a new one if needed */
195 nv->pctx_id = -1;
196 for (i = 0; i < nvc->nr_pctx; i++) {
197 if (nvc->pctx[i] == NULL) {
198 nv->pctx_id = i;
199 break;
200 }
201 }
202
203 if (nv->pctx_id < 0) {
204 nv->pctx_id = nvc->nr_pctx++;
205 nvc->pctx =
206 realloc(nvc->pctx,
207 sizeof(struct pipe_context *) * nvc->nr_pctx);
208 }
209
210 /* Create pipe */
211 switch (dev->chipset & 0xf0) {
212 case 0x50:
213 case 0x80:
214 case 0x90:
215 if (nouveau_surface_init_nv50(nv))
216 return 1;
217 break;
218 default:
219 if (nouveau_surface_init_nv04(nv))
220 return 1;
221 break;
222 }
223
224 if (!getenv("NOUVEAU_FORCE_SOFTPIPE")) {
225 struct pipe_screen *pscreen;
226
227 pipe = nouveau_pipe_create(nv);
228 if (!pipe)
229 NOUVEAU_ERR("Couldn't create hw pipe\n");
230 pscreen = nvc->pscreen;
231
232 nv->cap.hw_vertex_buffer =
233 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_VTXBUF);
234 nv->cap.hw_index_buffer =
235 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF);
236 }
237
238 /* XXX: nouveau_winsys_softpipe needs a mesa header removed before we can compile it. */
239 /*
240 if (!pipe) {
241 NOUVEAU_MSG("Using softpipe\n");
242 pipe = nouveau_create_softpipe(nv);
243 if (!pipe) {
244 NOUVEAU_ERR("Error creating pipe, bailing\n");
245 return 1;
246 }
247 }
248 */
249 if (!pipe) {
250 NOUVEAU_ERR("Error creating pipe, bailing\n");
251 return 1;
252 }
253
254 pipe->priv = nv;
255
256 return 0;
257 }
258
259 void
260 nouveau_context_destroy(dri_context_t *dri_context)
261 {
262 struct nouveau_context *nv = dri_context->private;
263 struct nouveau_channel_context *nvc = nv->nvc;
264
265 assert(nv);
266
267 if (nv->pctx_id >= 0) {
268 nvc->pctx[nv->pctx_id] = NULL;
269 if (--nvc->refcount <= 0) {
270 nouveau_channel_context_destroy(nvc);
271 nv->nv_screen->nvc = NULL;
272 }
273 }
274
275 free(nv);
276 }
277
278 int
279 nouveau_context_bind(struct nouveau_context *nv, dri_drawable_t *dri_drawable)
280 {
281 assert(nv);
282 assert(dri_drawable);
283
284 if (nv->dri_drawable != dri_drawable)
285 {
286 nv->dri_drawable = dri_drawable;
287 dri_drawable->private = nv;
288 }
289
290 return 0;
291 }
292
293 int
294 nouveau_context_unbind(struct nouveau_context *nv)
295 {
296 assert(nv);
297
298 nv->dri_drawable = NULL;
299
300 return 0;
301 }
302
303 /* Show starts here */
304
305 int bind_pipe_drawable(struct pipe_context *pipe, Drawable drawable)
306 {
307 struct nouveau_context *nv;
308 dri_drawable_t *dri_drawable;
309
310 nv = pipe->priv;
311
312 driCreateDrawable(nv->nv_screen->dri_screen, drawable, &dri_drawable);
313
314 nouveau_context_bind(nv, dri_drawable);
315
316 return 0;
317 }
318
319 int unbind_pipe_drawable(struct pipe_context *pipe)
320 {
321 nouveau_context_unbind(pipe->priv);
322
323 return 0;
324 }
325
326 struct pipe_context* create_pipe_context(Display *display, int screen)
327 {
328 dri_screen_t *dri_screen;
329 dri_framebuffer_t dri_framebuf;
330 dri_context_t *dri_context;
331 struct nouveau_context *nv;
332
333 driCreateScreen(display, screen, &dri_screen, &dri_framebuf);
334 driCreateContext(dri_screen, XDefaultVisual(display, screen), &dri_context);
335
336 nouveau_screen_create(dri_screen, &dri_framebuf);
337 nouveau_context_create(dri_context);
338
339 nv = dri_context->private;
340
341 return nv->nvc->pctx[nv->pctx_id];
342 }
343
344 int destroy_pipe_context(struct pipe_context *pipe)
345 {
346 struct pipe_screen *screen;
347 struct pipe_winsys *winsys;
348 struct nouveau_context *nv;
349 dri_screen_t *dri_screen;
350 dri_context_t *dri_context;
351
352 assert(pipe);
353
354 screen = pipe->screen;
355 winsys = pipe->winsys;
356 nv = pipe->priv;
357 dri_context = nv->dri_context;
358 dri_screen = dri_context->dri_screen;
359
360 pipe->destroy(pipe);
361 screen->destroy(screen);
362 free(winsys);
363
364 nouveau_context_destroy(dri_context);
365 nouveau_screen_destroy(dri_screen);
366 driDestroyContext(dri_context);
367 driDestroyScreen(dri_screen);
368
369 return 0;
370 }
371