1 /**************************************************************************
2 *
3 * Copyright 2012 Francisco Jerez
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #ifdef HAVE_DRISW_KMS
29 #include <fcntl.h>
30 #endif
31
32 #include "pipe_loader_priv.h"
33
34 #include "util/os_file.h"
35 #include "util/u_memory.h"
36 #include "util/u_dl.h"
37 #include "sw/dri/dri_sw_winsys.h"
38 #include "sw/kms-dri/kms_dri_sw_winsys.h"
39 #include "sw/null/null_sw_winsys.h"
40 #include "sw/wrapper/wrapper_sw_winsys.h"
41 #include "target-helpers/sw_helper_public.h"
42 #include "target-helpers/inline_debug_helper.h"
43 #include "frontend/drisw_api.h"
44 #include "frontend/sw_driver.h"
45 #include "frontend/sw_winsys.h"
46 #include "util/driconf.h"
47
48 struct pipe_loader_sw_device {
49 struct pipe_loader_device base;
50 const struct sw_driver_descriptor *dd;
51 #ifndef GALLIUM_STATIC_TARGETS
52 struct util_dl_library *lib;
53 #endif
54 struct sw_winsys *ws;
55 int fd;
56 };
57
58 #define pipe_loader_sw_device(dev) ((struct pipe_loader_sw_device *)dev)
59
60 static const struct pipe_loader_ops pipe_loader_sw_ops;
61 #if defined(HAVE_DRI) && defined(HAVE_ZINK)
62 static const struct pipe_loader_ops pipe_loader_vk_ops;
63 #endif
64
65 #ifdef GALLIUM_STATIC_TARGETS
66 static const struct sw_driver_descriptor driver_descriptors = {
67 .create_screen = sw_screen_create_vk,
68 .winsys = {
69 #ifdef HAVE_DRI
70 {
71 .name = "dri",
72 .create_winsys = dri_create_sw_winsys,
73 },
74 #endif
75 #ifdef HAVE_DRISW_KMS
76 {
77 .name = "kms_dri",
78 .create_winsys = kms_dri_create_winsys,
79 },
80 #endif
81 #ifndef __ANDROID__
82 {
83 .name = "null",
84 .create_winsys = null_sw_create,
85 },
86 {
87 .name = "wrapped",
88 .create_winsys = wrapper_sw_winsys_wrap_pipe_screen,
89 },
90 #endif
91 { 0 },
92 }
93 };
94 #endif
95
96 #if defined(GALLIUM_STATIC_TARGETS) && defined(HAVE_ZINK) && defined(HAVE_DRI)
97 static const struct sw_driver_descriptor kopper_driver_descriptors = {
98 .create_screen = sw_screen_create_zink,
99 .winsys = {
100 {
101 .name = "dri",
102 .create_winsys = dri_create_sw_winsys,
103 },
104 #ifdef HAVE_DRISW_KMS
105 {
106 .name = "kms_dri",
107 .create_winsys = kms_dri_create_winsys,
108 },
109 #endif
110 #ifndef __ANDROID__
111 {
112 .name = "null",
113 .create_winsys = null_sw_create,
114 },
115 {
116 .name = "wrapped",
117 .create_winsys = wrapper_sw_winsys_wrap_pipe_screen,
118 },
119 #endif
120 { 0 },
121 }
122 };
123 #endif
124
125 static bool
pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device * sdev)126 pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device *sdev)
127 {
128 sdev->base.type = PIPE_LOADER_DEVICE_SOFTWARE;
129 sdev->base.driver_name = "swrast";
130 sdev->base.ops = &pipe_loader_sw_ops;
131 sdev->fd = -1;
132
133 #ifdef GALLIUM_STATIC_TARGETS
134 sdev->dd = &driver_descriptors;
135 if (!sdev->dd)
136 return false;
137 #else
138 const char *search_dir = getenv("GALLIUM_PIPE_SEARCH_DIR");
139 if (search_dir == NULL)
140 search_dir = PIPE_SEARCH_DIR;
141
142 sdev->lib = pipe_loader_find_module("swrast", search_dir);
143 if (!sdev->lib)
144 return false;
145
146 sdev->dd = (const struct sw_driver_descriptor *)
147 util_dl_get_proc_address(sdev->lib, "swrast_driver_descriptor");
148
149 if (!sdev->dd){
150 util_dl_close(sdev->lib);
151 sdev->lib = NULL;
152 return false;
153 }
154 #endif
155
156 return true;
157 }
158
159 #if defined(HAVE_DRI) && defined(HAVE_ZINK)
160 static bool
pipe_loader_vk_probe_init_common(struct pipe_loader_sw_device * sdev)161 pipe_loader_vk_probe_init_common(struct pipe_loader_sw_device *sdev)
162 {
163 sdev->base.type = PIPE_LOADER_DEVICE_PLATFORM;
164 sdev->base.driver_name = "kopper";
165 sdev->base.ops = &pipe_loader_vk_ops;
166 sdev->fd = -1;
167
168 #ifdef GALLIUM_STATIC_TARGETS
169 sdev->dd = &kopper_driver_descriptors;
170 if (!sdev->dd)
171 return false;
172 #else
173 const char *search_dir = getenv("GALLIUM_PIPE_SEARCH_DIR");
174 if (search_dir == NULL)
175 search_dir = PIPE_SEARCH_DIR;
176
177 sdev->lib = pipe_loader_find_module("swrast", search_dir);
178 if (!sdev->lib)
179 return false;
180
181 sdev->dd = (const struct sw_driver_descriptor *)
182 util_dl_get_proc_address(sdev->lib, "swrast_driver_descriptor");
183
184 if (!sdev->dd){
185 util_dl_close(sdev->lib);
186 sdev->lib = NULL;
187 return false;
188 }
189 #endif
190
191 return true;
192 }
193 #endif
194
195 static void
pipe_loader_sw_probe_teardown_common(struct pipe_loader_sw_device * sdev)196 pipe_loader_sw_probe_teardown_common(struct pipe_loader_sw_device *sdev)
197 {
198 #ifndef GALLIUM_STATIC_TARGETS
199 if (sdev->lib)
200 util_dl_close(sdev->lib);
201 #endif
202 }
203
204 #ifdef HAVE_DRI
205 bool
pipe_loader_sw_probe_dri(struct pipe_loader_device ** devs,const struct drisw_loader_funcs * drisw_lf)206 pipe_loader_sw_probe_dri(struct pipe_loader_device **devs, const struct drisw_loader_funcs *drisw_lf)
207 {
208 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
209 int i;
210
211 if (!sdev)
212 return false;
213
214 if (!pipe_loader_sw_probe_init_common(sdev))
215 goto fail;
216
217 for (i = 0; sdev->dd->winsys[i].name; i++) {
218 if (strcmp(sdev->dd->winsys[i].name, "dri") == 0) {
219 sdev->ws = sdev->dd->winsys[i].create_winsys(drisw_lf);
220 break;
221 }
222 }
223 if (!sdev->ws)
224 goto fail;
225
226 *devs = &sdev->base;
227 return true;
228
229 fail:
230 pipe_loader_sw_probe_teardown_common(sdev);
231 FREE(sdev);
232 return false;
233 }
234 #ifdef HAVE_ZINK
235 bool
pipe_loader_vk_probe_dri(struct pipe_loader_device ** devs,const struct drisw_loader_funcs * drisw_lf)236 pipe_loader_vk_probe_dri(struct pipe_loader_device **devs, const struct drisw_loader_funcs *drisw_lf)
237 {
238 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
239 int i;
240
241 if (!sdev)
242 return false;
243
244 if (!pipe_loader_vk_probe_init_common(sdev))
245 goto fail;
246
247 for (i = 0; sdev->dd->winsys[i].name; i++) {
248 if (strcmp(sdev->dd->winsys[i].name, "dri") == 0) {
249 sdev->ws = sdev->dd->winsys[i].create_winsys(drisw_lf);
250 break;
251 }
252 }
253 if (!sdev->ws)
254 goto fail;
255
256 *devs = &sdev->base;
257 return true;
258
259 fail:
260 pipe_loader_sw_probe_teardown_common(sdev);
261 FREE(sdev);
262 return false;
263 }
264 #endif
265 #endif
266
267 #ifdef HAVE_DRISW_KMS
268 bool
pipe_loader_sw_probe_kms(struct pipe_loader_device ** devs,int fd)269 pipe_loader_sw_probe_kms(struct pipe_loader_device **devs, int fd)
270 {
271 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
272 int i;
273
274 if (!sdev)
275 return false;
276
277 if (!pipe_loader_sw_probe_init_common(sdev))
278 goto fail;
279
280 if (fd < 0 || (sdev->fd = os_dupfd_cloexec(fd)) < 0)
281 goto fail;
282
283 for (i = 0; sdev->dd->winsys[i].name; i++) {
284 if (strcmp(sdev->dd->winsys[i].name, "kms_dri") == 0) {
285 sdev->ws = sdev->dd->winsys[i].create_winsys(sdev->fd);
286 break;
287 }
288 }
289 if (!sdev->ws)
290 goto fail;
291
292 *devs = &sdev->base;
293 return true;
294
295 fail:
296 pipe_loader_sw_probe_teardown_common(sdev);
297 if (sdev->fd != -1)
298 close(sdev->fd);
299 FREE(sdev);
300 return false;
301 }
302 #endif
303
304 bool
pipe_loader_sw_probe_null(struct pipe_loader_device ** devs)305 pipe_loader_sw_probe_null(struct pipe_loader_device **devs)
306 {
307 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
308 int i;
309
310 if (!sdev)
311 return false;
312
313 if (!pipe_loader_sw_probe_init_common(sdev))
314 goto fail;
315
316 for (i = 0; sdev->dd->winsys[i].name; i++) {
317 if (strcmp(sdev->dd->winsys[i].name, "null") == 0) {
318 sdev->ws = sdev->dd->winsys[i].create_winsys();
319 break;
320 }
321 }
322 if (!sdev->ws)
323 goto fail;
324
325 *devs = &sdev->base;
326 return true;
327
328 fail:
329 pipe_loader_sw_probe_teardown_common(sdev);
330 FREE(sdev);
331 return false;
332 }
333
334 int
pipe_loader_sw_probe(struct pipe_loader_device ** devs,int ndev)335 pipe_loader_sw_probe(struct pipe_loader_device **devs, int ndev)
336 {
337 int i = 1;
338
339 if (i <= ndev) {
340 if (!pipe_loader_sw_probe_null(devs)) {
341 i--;
342 }
343 }
344
345 return i;
346 }
347
348 boolean
pipe_loader_sw_probe_wrapped(struct pipe_loader_device ** dev,struct pipe_screen * screen)349 pipe_loader_sw_probe_wrapped(struct pipe_loader_device **dev,
350 struct pipe_screen *screen)
351 {
352 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
353 int i;
354
355 if (!sdev)
356 return false;
357
358 if (!pipe_loader_sw_probe_init_common(sdev))
359 goto fail;
360
361 for (i = 0; sdev->dd->winsys[i].name; i++) {
362 if (strcmp(sdev->dd->winsys[i].name, "wrapped") == 0) {
363 sdev->ws = sdev->dd->winsys[i].create_winsys(screen);
364 break;
365 }
366 }
367 if (!sdev->ws)
368 goto fail;
369
370 *dev = &sdev->base;
371 return true;
372
373 fail:
374 pipe_loader_sw_probe_teardown_common(sdev);
375 FREE(sdev);
376 return false;
377 }
378
379 static void
pipe_loader_sw_release(struct pipe_loader_device ** dev)380 pipe_loader_sw_release(struct pipe_loader_device **dev)
381 {
382 UNUSED struct pipe_loader_sw_device *sdev =
383 pipe_loader_sw_device(*dev);
384
385 #ifndef GALLIUM_STATIC_TARGETS
386 if (sdev->lib)
387 util_dl_close(sdev->lib);
388 #endif
389
390 #ifdef HAVE_DRISW_KMS
391 if (sdev->fd != -1)
392 close(sdev->fd);
393 #endif
394
395 pipe_loader_base_release(dev);
396 }
397
398 static const struct driOptionDescription *
pipe_loader_sw_get_driconf(struct pipe_loader_device * dev,unsigned * count)399 pipe_loader_sw_get_driconf(struct pipe_loader_device *dev, unsigned *count)
400 {
401 *count = 0;
402 return NULL;
403 }
404
405 #if defined(HAVE_DRI) && defined(HAVE_ZINK)
406 static const driOptionDescription zink_driconf[] = {
407 #include "gallium/drivers/zink/driinfo_zink.h"
408 };
409
410 static const struct driOptionDescription *
pipe_loader_vk_get_driconf(struct pipe_loader_device * dev,unsigned * count)411 pipe_loader_vk_get_driconf(struct pipe_loader_device *dev, unsigned *count)
412 {
413 *count = ARRAY_SIZE(zink_driconf);
414 return zink_driconf;
415 }
416 #endif
417
418 static struct pipe_screen *
pipe_loader_sw_create_screen(struct pipe_loader_device * dev,const struct pipe_screen_config * config,bool sw_vk)419 pipe_loader_sw_create_screen(struct pipe_loader_device *dev,
420 const struct pipe_screen_config *config, bool sw_vk)
421 {
422 struct pipe_loader_sw_device *sdev = pipe_loader_sw_device(dev);
423 struct pipe_screen *screen;
424
425 screen = sdev->dd->create_screen(sdev->ws, config, sw_vk);
426 if (!screen)
427 sdev->ws->destroy(sdev->ws);
428
429 return screen ? debug_screen_wrap(screen) : NULL;
430 }
431
432 static const struct pipe_loader_ops pipe_loader_sw_ops = {
433 .create_screen = pipe_loader_sw_create_screen,
434 .get_driconf = pipe_loader_sw_get_driconf,
435 .release = pipe_loader_sw_release
436 };
437
438 #if defined(HAVE_DRI) && defined(HAVE_ZINK)
439 static const struct pipe_loader_ops pipe_loader_vk_ops = {
440 .create_screen = pipe_loader_sw_create_screen,
441 .get_driconf = pipe_loader_vk_get_driconf,
442 .release = pipe_loader_sw_release
443 };
444 #endif
445