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