d467305d4c0f6fa786e4b9ca653072c3799ee7c8
[mesa.git] / src / gallium / winsys / drm / nouveau / drm / nouveau_drm_api.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "util/u_memory.h"
4
5 #include "nouveau_drm_api.h"
6
7 #include "nouveau_drmif.h"
8 #include "nouveau_channel.h"
9 #include "nouveau_bo.h"
10
11 #include "nouveau/nouveau_winsys.h"
12 #include "nouveau/nouveau_screen.h"
13
14 static struct pipe_surface *
15 dri_surface_from_handle(struct drm_api *api, struct pipe_screen *pscreen,
16 unsigned handle, enum pipe_format format,
17 unsigned width, unsigned height, unsigned pitch)
18 {
19 struct pipe_surface *ps = NULL;
20 struct pipe_texture *pt = NULL;
21 struct pipe_texture tmpl;
22
23 memset(&tmpl, 0, sizeof(tmpl));
24 tmpl.tex_usage = PIPE_TEXTURE_USAGE_PRIMARY;
25 tmpl.target = PIPE_TEXTURE_2D;
26 tmpl.last_level = 0;
27 tmpl.depth0 = 1;
28 tmpl.format = format;
29 tmpl.width0 = width;
30 tmpl.height0 = height;
31
32 pt = api->texture_from_shared_handle(api, pscreen, &tmpl,
33 "front buffer", pitch, handle);
34 if (!pt)
35 return NULL;
36
37 ps = pscreen->get_tex_surface(pscreen, pt, 0, 0, 0,
38 PIPE_BUFFER_USAGE_GPU_READ |
39 PIPE_BUFFER_USAGE_GPU_WRITE);
40
41 /* we don't need the texture from this point on */
42 pipe_texture_reference(&pt, NULL);
43 return ps;
44 }
45
46 static struct pipe_surface *
47 nouveau_dri1_front_surface(struct pipe_screen *screen)
48 {
49 return nouveau_winsys_screen(screen)->front;
50 }
51
52 static struct dri1_api nouveau_dri1_api = {
53 nouveau_dri1_front_surface,
54 };
55
56 static struct pipe_screen *
57 nouveau_drm_create_screen(struct drm_api *api, int fd,
58 struct drm_create_screen_arg *arg)
59 {
60 struct dri1_create_screen_arg *dri1 = (void *)arg;
61 struct nouveau_winsys *nvws;
62 struct pipe_winsys *ws;
63 struct nouveau_device *dev = NULL;
64 struct pipe_screen *(*init)(struct pipe_winsys *,
65 struct nouveau_device *);
66 int ret;
67
68 ret = nouveau_device_open_existing(&dev, 0, fd, 0);
69 if (ret)
70 return NULL;
71
72 switch (dev->chipset & 0xf0) {
73 case 0x00:
74 init = nv04_screen_create;
75 break;
76 case 0x10:
77 init = nv10_screen_create;
78 break;
79 case 0x20:
80 init = nv20_screen_create;
81 break;
82 case 0x30:
83 init = nv30_screen_create;
84 break;
85 case 0x40:
86 case 0x60:
87 init = nv40_screen_create;
88 break;
89 case 0x80:
90 case 0x90:
91 case 0xa0:
92 init = nv50_screen_create;
93 break;
94 default:
95 debug_printf("%s: unknown chipset nv%02x\n", __func__,
96 dev->chipset);
97 return NULL;
98 }
99
100 nvws = CALLOC_STRUCT(nouveau_winsys);
101 if (!nvws) {
102 nouveau_device_close(&dev);
103 return NULL;
104 }
105 ws = &nvws->base;
106
107 nvws->pscreen = init(ws, dev);
108 if (!nvws->pscreen) {
109 ws->destroy(ws);
110 return NULL;
111 }
112
113 if (arg && arg->mode == DRM_CREATE_DRI1) {
114 struct nouveau_dri *nvdri = dri1->ddx_info;
115 enum pipe_format format;
116
117 if (nvdri->bpp == 16)
118 format = PIPE_FORMAT_R5G6B5_UNORM;
119 else
120 format = PIPE_FORMAT_A8R8G8B8_UNORM;
121
122 nvws->front = dri_surface_from_handle(api, nvws->pscreen,
123 nvdri->front_offset,
124 format, nvdri->width,
125 nvdri->height,
126 nvdri->front_pitch *
127 (nvdri->bpp / 8));
128 if (!nvws->front) {
129 debug_printf("%s: error referencing front buffer\n",
130 __func__);
131 ws->destroy(ws);
132 return NULL;
133 }
134
135 dri1->api = &nouveau_dri1_api;
136 }
137
138 return nvws->pscreen;
139 }
140
141 static struct pipe_context *
142 nouveau_drm_create_context(struct drm_api *api, struct pipe_screen *pscreen)
143 {
144 struct nouveau_winsys *nvws = nouveau_winsys_screen(pscreen);
145 struct pipe_context *(*init)(struct pipe_screen *, unsigned);
146 unsigned chipset = nouveau_screen(pscreen)->device->chipset;
147 int i;
148
149 switch (chipset & 0xf0) {
150 case 0x00:
151 init = nv04_create;
152 break;
153 case 0x10:
154 init = nv10_create;
155 break;
156 case 0x20:
157 init = nv20_create;
158 break;
159 case 0x30:
160 init = nv30_create;
161 break;
162 case 0x40:
163 case 0x60:
164 init = nv40_create;
165 break;
166 case 0x80:
167 case 0x90:
168 case 0xa0:
169 init = nv50_create;
170 break;
171 default:
172 debug_printf("%s: unknown chipset nv%02x\n", __func__, chipset);
173 return NULL;
174 }
175
176 /* Find a free slot for a pipe context, allocate a new one if needed */
177 for (i = 0; i < nvws->nr_pctx; i++) {
178 if (nvws->pctx[i] == NULL)
179 break;
180 }
181
182 if (i == nvws->nr_pctx) {
183 nvws->nr_pctx++;
184 nvws->pctx = realloc(nvws->pctx,
185 sizeof(*nvws->pctx) * nvws->nr_pctx);
186 }
187
188 nvws->pctx[i] = init(pscreen, i);
189 return nvws->pctx[i];
190 }
191
192 typedef struct pipe_video_context* (*nouveau_video_create)(struct pipe_context *pipe,
193 enum pipe_video_profile profile,
194 enum pipe_video_chroma_format chroma_format,
195 unsigned width, unsigned height,
196 unsigned pvctx);
197
198 static struct pipe_video_context *
199 nouveau_drm_create_video_context(struct drm_api *api, struct pipe_screen *pscreen,
200 enum pipe_video_profile profile,
201 enum pipe_video_chroma_format chroma_format,
202 unsigned width, unsigned height)
203 {
204 struct nouveau_winsys *nvws = nouveau_winsys_screen(pscreen);
205 nouveau_video_create init;
206 unsigned chipset = nouveau_screen(pscreen)->device->chipset;
207 struct pipe_context *pipe;
208 int i;
209
210 switch (chipset & 0xf0) {
211 case 0x40:
212 case 0x60:
213 init = nv40_video_create;
214 break;
215 default:
216 debug_printf("%s: unknown chipset nv%02x\n", __func__, chipset);
217 return NULL;
218 }
219
220 /* Find a free slot for a pipe video context, allocate a new one if needed */
221 for (i = 0; i < nvws->nr_pvctx; i++) {
222 if (nvws->pvctx[i] == NULL)
223 break;
224 }
225
226 if (i == nvws->nr_pvctx) {
227 nvws->nr_pvctx++;
228 nvws->pvctx = realloc(nvws->pvctx,
229 sizeof(*nvws->pvctx) * nvws->nr_pvctx);
230 }
231
232 pipe = nouveau_drm_create_context(api, pscreen);
233 if (!pipe)
234 return NULL;
235
236 nvws->pvctx[i] = init(pipe, profile, chroma_format, width, height, i);
237 return nvws->pvctx[i];
238 }
239
240 static struct pipe_texture *
241 nouveau_drm_pt_from_name(struct drm_api *api, struct pipe_screen *pscreen,
242 struct pipe_texture *templ, const char *name,
243 unsigned stride, unsigned handle)
244 {
245 struct nouveau_device *dev = nouveau_screen(pscreen)->device;
246 struct pipe_texture *pt;
247 struct pipe_buffer *pb;
248 int ret;
249
250 pb = CALLOC(1, sizeof(struct pipe_buffer) + sizeof(struct nouveau_bo*));
251 if (!pb)
252 return NULL;
253
254 ret = nouveau_bo_handle_ref(dev, handle, (struct nouveau_bo**)(pb+1));
255 if (ret) {
256 debug_printf("%s: ref name 0x%08x failed with %d\n",
257 __func__, handle, ret);
258 FREE(pb);
259 return NULL;
260 }
261
262 pipe_reference_init(&pb->reference, 1);
263 pb->screen = pscreen;
264 pb->alignment = 0;
265 pb->usage = PIPE_BUFFER_USAGE_GPU_READ_WRITE |
266 PIPE_BUFFER_USAGE_CPU_READ_WRITE;
267 pb->size = nouveau_bo(pb)->size;
268 pt = pscreen->texture_blanket(pscreen, templ, &stride, pb);
269 pipe_buffer_reference(&pb, NULL);
270 return pt;
271 }
272
273 static boolean
274 nouveau_drm_name_from_pt(struct drm_api *api, struct pipe_screen *pscreen,
275 struct pipe_texture *pt, unsigned *stride,
276 unsigned *handle)
277 {
278 struct nouveau_miptree *mt = nouveau_miptree(pt);
279
280 if (!mt || !mt->bo)
281 return false;
282
283 return nouveau_bo_handle_get(mt->bo, handle) == 0;
284 }
285
286 static boolean
287 nouveau_drm_handle_from_pt(struct drm_api *api, struct pipe_screen *pscreen,
288 struct pipe_texture *pt, unsigned *stride,
289 unsigned *handle)
290 {
291 struct nouveau_miptree *mt = nouveau_miptree(pt);
292
293 if (!mt || !mt->bo)
294 return false;
295
296 *handle = mt->bo->handle;
297 *stride = pf_get_stride(mt->base.format, mt->base.width0);
298 return true;
299 }
300
301 struct drm_api drm_api_hooks = {
302 .create_screen = nouveau_drm_create_screen,
303 .create_context = nouveau_drm_create_context,
304 .create_video_context = nouveau_drm_create_video_context,
305 .texture_from_shared_handle = nouveau_drm_pt_from_name,
306 .shared_handle_from_texture = nouveau_drm_name_from_pt,
307 .local_handle_from_texture = nouveau_drm_handle_from_pt,
308 };
309
310 struct drm_api *
311 drm_api_create() {
312 return &drm_api_hooks;
313 }
314