70f005b8880eb157805526038e70dfe0f2e8d0d3
[mesa.git] / src / gallium / winsys / drm / nouveau / common / nouveau_context.c
1 #include <pipe/p_defines.h>
2 #include <pipe/p_context.h>
3 #include <pipe/p_screen.h>
4 #include <util/u_memory.h>
5 #include "nouveau_context.h"
6 #include "nouveau_dri.h"
7 #include "nouveau_local.h"
8 #include "nouveau_screen.h"
9 #include "nouveau_winsys_pipe.h"
10
11 static void
12 nouveau_channel_context_destroy(struct nouveau_channel_context *nvc)
13 {
14 nouveau_grobj_free(&nvc->NvCtxSurf2D);
15 nouveau_grobj_free(&nvc->NvImageBlit);
16 nouveau_grobj_free(&nvc->NvGdiRect);
17 nouveau_grobj_free(&nvc->NvM2MF);
18 nouveau_grobj_free(&nvc->Nv2D);
19 nouveau_grobj_free(&nvc->NvSwzSurf);
20 nouveau_grobj_free(&nvc->NvSIFM);
21
22 nouveau_notifier_free(&nvc->sync_notifier);
23
24 nouveau_channel_free(&nvc->channel);
25
26 FREE(nvc);
27 }
28
29 static struct nouveau_channel_context *
30 nouveau_channel_context_create(struct nouveau_device *dev)
31 {
32 struct nouveau_channel_context *nvc;
33 int ret;
34
35 nvc = CALLOC_STRUCT(nouveau_channel_context);
36 if (!nvc)
37 return NULL;
38
39 if ((ret = nouveau_channel_alloc(dev, 0x8003d001, 0x8003d002,
40 &nvc->channel))) {
41 NOUVEAU_ERR("Error creating GPU channel: %d\n", ret);
42 nouveau_channel_context_destroy(nvc);
43 return NULL;
44 }
45
46 nvc->next_handle = 0x88000000;
47
48 if ((ret = nouveau_notifier_alloc(nvc->channel, nvc->next_handle++, 1,
49 &nvc->sync_notifier))) {
50 NOUVEAU_ERR("Error creating channel sync notifier: %d\n", ret);
51 nouveau_channel_context_destroy(nvc);
52 return NULL;
53 }
54
55 switch (dev->chipset & 0xf0) {
56 case 0x50:
57 case 0x80:
58 case 0x90:
59 ret = nouveau_surface_channel_create_nv50(nvc);
60 break;
61 default:
62 ret = nouveau_surface_channel_create_nv04(nvc);
63 break;
64 }
65
66 if (ret) {
67 NOUVEAU_ERR("Error initialising surface objects: %d\n", ret);
68 nouveau_channel_context_destroy(nvc);
69 return NULL;
70 }
71
72 return nvc;
73 }
74
75 int
76 nouveau_context_init(struct nouveau_screen *nv_screen,
77 drm_context_t hHWContext, drmLock *sarea_lock,
78 struct nouveau_context *nv_share,
79 struct nouveau_context *nv)
80 {
81 struct pipe_context *pipe = NULL;
82 struct nouveau_channel_context *nvc = NULL;
83 struct nouveau_device *dev = nv_screen->device;
84 int i;
85
86 switch (dev->chipset & 0xf0) {
87 case 0x00:
88 /* NV04 */
89 case 0x10:
90 case 0x20:
91 /* NV10 */
92 case 0x30:
93 /* NV30 */
94 case 0x40:
95 case 0x60:
96 /* NV40 */
97 case 0x50:
98 case 0x80:
99 case 0x90:
100 /* G80 */
101 break;
102 default:
103 NOUVEAU_ERR("Unsupported chipset: NV%02x\n", dev->chipset);
104 return 1;
105 }
106
107 nv->nv_screen = nv_screen;
108
109 {
110 struct nouveau_device_priv *nvdev = nouveau_device(dev);
111
112 nvdev->ctx = hHWContext;
113 nvdev->lock = sarea_lock;
114 }
115
116 /* Attempt to share a single channel between multiple contexts from
117 * a single process.
118 */
119 nvc = nv_screen->nvc;
120 if (!nvc && nv_share)
121 nvc = nv_share->nvc;
122
123 /*XXX: temporary - disable multi-context/single-channel on pre-NV4x */
124 switch (dev->chipset & 0xf0) {
125 case 0x40:
126 case 0x60:
127 /* NV40 class */
128 case 0x50:
129 case 0x80:
130 case 0x90:
131 /* G80 class */
132 break;
133 default:
134 nvc = NULL;
135 break;
136 }
137
138 if (!nvc) {
139 nvc = nouveau_channel_context_create(dev);
140 if (!nvc) {
141 NOUVEAU_ERR("Failed initialising GPU context\n");
142 return 1;
143 }
144 nv_screen->nvc = nvc;
145 }
146
147 nvc->refcount++;
148 nv->nvc = nvc;
149
150 /* Find a free slot for a pipe context, allocate a new one if needed */
151 nv->pctx_id = -1;
152 for (i = 0; i < nvc->nr_pctx; i++) {
153 if (nvc->pctx[i] == NULL) {
154 nv->pctx_id = i;
155 break;
156 }
157 }
158
159 if (nv->pctx_id < 0) {
160 nv->pctx_id = nvc->nr_pctx++;
161 nvc->pctx =
162 realloc(nvc->pctx,
163 sizeof(struct pipe_context *) * nvc->nr_pctx);
164 }
165
166 /* Create pipe */
167 switch (dev->chipset & 0xf0) {
168 case 0x50:
169 case 0x80:
170 case 0x90:
171 if (nouveau_surface_init_nv50(nv))
172 return 1;
173 break;
174 default:
175 if (nouveau_surface_init_nv04(nv))
176 return 1;
177 break;
178 }
179
180 if (!getenv("NOUVEAU_FORCE_SOFTPIPE")) {
181 struct pipe_screen *pscreen;
182
183 pipe = nouveau_pipe_create(nv);
184 if (!pipe)
185 NOUVEAU_ERR("Couldn't create hw pipe\n");
186 pscreen = nvc->pscreen;
187
188 nv->cap.hw_vertex_buffer =
189 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_VTXBUF);
190 nv->cap.hw_index_buffer =
191 pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF);
192 }
193
194 if (!pipe) {
195 NOUVEAU_MSG("Using softpipe\n");
196 pipe = nouveau_create_softpipe(nv);
197 if (!pipe) {
198 NOUVEAU_ERR("Error creating pipe, bailing\n");
199 return 1;
200 }
201 }
202
203 {
204 struct pipe_texture *fb_tex;
205 struct pipe_surface *fb_surf;
206 struct nouveau_pipe_buffer *fb_buf;
207 enum pipe_format format;
208
209 fb_buf = calloc(1, sizeof(struct nouveau_pipe_buffer));
210 fb_buf->base.refcount = 1;
211 fb_buf->base.usage = PIPE_BUFFER_USAGE_PIXEL;
212
213 nouveau_bo_fake(dev, nv_screen->front_offset, NOUVEAU_BO_VRAM,
214 nv_screen->front_pitch*nv_screen->front_height,
215 NULL, &fb_buf->bo);
216
217 if (nv_screen->front_cpp == 4)
218 format = PIPE_FORMAT_A8R8G8B8_UNORM;
219 else
220 format = PIPE_FORMAT_R5G6B5_UNORM;
221
222 fb_surf = nouveau_surface_buffer_ref(nv, &fb_buf->base, format,
223 nv_screen->front_pitch /
224 nv_screen->front_cpp,
225 nv_screen->front_height,
226 nv_screen->front_pitch,
227 &fb_tex);
228
229 nv->frontbuffer = fb_surf;
230 nv->frontbuffer_texture = fb_tex;
231 }
232
233 pipe->priv = nv;
234 return 0;
235 }
236
237 void
238 nouveau_context_cleanup(struct nouveau_context *nv)
239 {
240 struct nouveau_channel_context *nvc = nv->nvc;
241
242 assert(nv);
243
244 if (nv->pctx_id >= 0) {
245 nvc->pctx[nv->pctx_id] = NULL;
246 if (--nvc->refcount <= 0) {
247 nouveau_channel_context_destroy(nvc);
248 nv->nv_screen->nvc = NULL;
249 }
250 }
251
252 /* XXX: Who cleans up the pipe? */
253 }
254