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/detect_os.h"
35 #include "util/os_file.h"
36 #include "util/u_memory.h"
37 #include "util/u_dl.h"
38 #include "sw/dri/dri_sw_winsys.h"
39 #include "sw/kms-dri/kms_dri_sw_winsys.h"
40 #include "sw/null/null_sw_winsys.h"
41 #include "sw/wrapper/wrapper_sw_winsys.h"
42 #include "target-helpers/sw_helper_public.h"
43 #include "target-helpers/inline_debug_helper.h"
44 #include "frontend/drisw_api.h"
45 #include "frontend/sw_driver.h"
46 #include "frontend/sw_winsys.h"
47 #include "util/driconf.h"
48
49 struct pipe_loader_sw_device {
50 struct pipe_loader_device base;
51 const struct sw_driver_descriptor *dd;
52 #ifndef GALLIUM_STATIC_TARGETS
53 struct util_dl_library *lib;
54 #endif
55 struct sw_winsys *ws;
56 int fd;
57 };
58
59 #define pipe_loader_sw_device(dev) ((struct pipe_loader_sw_device *)dev)
60
61 static const struct pipe_loader_ops pipe_loader_sw_ops;
62 #if defined(HAVE_DRI) && defined(HAVE_ZINK)
63 static const struct pipe_loader_ops pipe_loader_vk_ops;
64 #endif
65
66 #ifdef GALLIUM_STATIC_TARGETS
67 static const struct sw_driver_descriptor driver_descriptors = {
68 .create_screen = sw_screen_create_vk,
69 .winsys = {
70 #ifdef HAVE_DRI
71 {
72 .name = "dri",
73 .create_winsys_dri = dri_create_sw_winsys,
74 },
75 #endif
76 #ifdef HAVE_DRISW_KMS
77 {
78 .name = "kms_dri",
79 .create_winsys_kms_dri = kms_dri_create_winsys,
80 },
81 #endif
82 #if !DETECT_OS_ANDROID
83 {
84 .name = "null",
85 .create_winsys = null_sw_create,
86 },
87 {
88 .name = "wrapped",
89 .create_winsys_wrapped = wrapper_sw_winsys_wrap_pipe_screen,
90 },
91 #endif
92 { 0 },
93 }
94 };
95 #endif
96
97 #if defined(GALLIUM_STATIC_TARGETS) && defined(HAVE_ZINK) && defined(HAVE_DRI)
98 static const struct sw_driver_descriptor kopper_driver_descriptors = {
99 .create_screen = sw_screen_create_zink,
100 .winsys = {
101 {
102 .name = "dri",
103 .create_winsys_dri = dri_create_sw_winsys,
104 },
105 #ifdef HAVE_DRISW_KMS
106 {
107 .name = "kms_dri",
108 .create_winsys_kms_dri = kms_dri_create_winsys,
109 },
110 #endif
111 #if !DETECT_OS_ANDROID
112 {
113 .name = "null",
114 .create_winsys = null_sw_create,
115 },
116 {
117 .name = "wrapped",
118 .create_winsys_wrapped = wrapper_sw_winsys_wrap_pipe_screen,
119 },
120 #endif
121 { 0 },
122 }
123 };
124 #endif
125
126 static bool
pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device * sdev)127 pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device *sdev)
128 {
129 sdev->base.type = PIPE_LOADER_DEVICE_SOFTWARE;
130 sdev->base.driver_name = "swrast";
131 sdev->base.ops = &pipe_loader_sw_ops;
132 sdev->fd = -1;
133
134 #ifdef GALLIUM_STATIC_TARGETS
135 sdev->dd = &driver_descriptors;
136 if (!sdev->dd)
137 return false;
138 #else
139 const char *search_dir = os_get_option("GALLIUM_PIPE_SEARCH_DIR");
140 if (search_dir == NULL)
141 search_dir = PIPE_SEARCH_DIR;
142
143 sdev->lib = pipe_loader_find_module("swrast", search_dir);
144 if (!sdev->lib)
145 return false;
146
147 sdev->dd = (const struct sw_driver_descriptor *)
148 util_dl_get_proc_address(sdev->lib, "swrast_driver_descriptor");
149
150 if (!sdev->dd){
151 util_dl_close(sdev->lib);
152 sdev->lib = NULL;
153 return false;
154 }
155 #endif
156
157 return true;
158 }
159
160 #if defined(HAVE_DRI) && defined(HAVE_ZINK)
161 static bool
pipe_loader_vk_probe_init_common(struct pipe_loader_sw_device * sdev)162 pipe_loader_vk_probe_init_common(struct pipe_loader_sw_device *sdev)
163 {
164 sdev->base.type = PIPE_LOADER_DEVICE_PLATFORM;
165 sdev->base.driver_name = "kopper";
166 sdev->base.ops = &pipe_loader_vk_ops;
167 sdev->fd = -1;
168
169 #ifdef GALLIUM_STATIC_TARGETS
170 sdev->dd = &kopper_driver_descriptors;
171 if (!sdev->dd)
172 return false;
173 #else
174 const char *search_dir = os_get_option("GALLIUM_PIPE_SEARCH_DIR");
175 if (search_dir == NULL)
176 search_dir = PIPE_SEARCH_DIR;
177
178 sdev->lib = pipe_loader_find_module("swrast", search_dir);
179 if (!sdev->lib)
180 return false;
181
182 sdev->dd = (const struct sw_driver_descriptor *)
183 util_dl_get_proc_address(sdev->lib, "swrast_driver_descriptor");
184
185 if (!sdev->dd){
186 util_dl_close(sdev->lib);
187 sdev->lib = NULL;
188 return false;
189 }
190 #endif
191
192 return true;
193 }
194 #endif
195
196 static void
pipe_loader_sw_probe_teardown_common(struct pipe_loader_sw_device * sdev)197 pipe_loader_sw_probe_teardown_common(struct pipe_loader_sw_device *sdev)
198 {
199 #ifndef GALLIUM_STATIC_TARGETS
200 if (sdev->lib)
201 util_dl_close(sdev->lib);
202 #endif
203 }
204
205 #ifdef HAVE_DRI
206 bool
pipe_loader_sw_probe_dri(struct pipe_loader_device ** devs,const struct drisw_loader_funcs * drisw_lf)207 pipe_loader_sw_probe_dri(struct pipe_loader_device **devs, const struct drisw_loader_funcs *drisw_lf)
208 {
209 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
210 int i;
211
212 if (!sdev)
213 return false;
214
215 if (!pipe_loader_sw_probe_init_common(sdev))
216 goto fail;
217
218 for (i = 0; sdev->dd->winsys[i].name; i++) {
219 if (strcmp(sdev->dd->winsys[i].name, "dri") == 0) {
220 sdev->ws = sdev->dd->winsys[i].create_winsys_dri(drisw_lf);
221 break;
222 }
223 }
224 if (!sdev->ws)
225 goto fail;
226
227 *devs = &sdev->base;
228 return true;
229
230 fail:
231 pipe_loader_sw_probe_teardown_common(sdev);
232 FREE(sdev);
233 return false;
234 }
235 #ifdef HAVE_ZINK
236 bool
pipe_loader_vk_probe_dri(struct pipe_loader_device ** devs)237 pipe_loader_vk_probe_dri(struct pipe_loader_device **devs)
238 {
239 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
240 int i;
241
242 if (!sdev)
243 return false;
244
245 if (!pipe_loader_vk_probe_init_common(sdev))
246 goto fail;
247
248 for (i = 0; sdev->dd->winsys[i].name; i++) {
249 if (strcmp(sdev->dd->winsys[i].name, "dri") == 0) {
250 sdev->ws = sdev->dd->winsys[i].create_winsys_dri(NULL);
251 break;
252 }
253 }
254 if (!sdev->ws)
255 goto fail;
256
257 *devs = &sdev->base;
258 return true;
259
260 fail:
261 pipe_loader_sw_probe_teardown_common(sdev);
262 FREE(sdev);
263 return false;
264 }
265 #endif
266 #endif
267
268 #ifdef HAVE_DRISW_KMS
269 bool
pipe_loader_sw_probe_kms(struct pipe_loader_device ** devs,int fd)270 pipe_loader_sw_probe_kms(struct pipe_loader_device **devs, int fd)
271 {
272 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
273 int i;
274
275 if (!sdev)
276 return false;
277
278 if (!pipe_loader_sw_probe_init_common(sdev))
279 goto fail;
280
281 if (fd < 0 || (sdev->fd = os_dupfd_cloexec(fd)) < 0)
282 goto fail;
283
284 for (i = 0; sdev->dd->winsys[i].name; i++) {
285 if (strcmp(sdev->dd->winsys[i].name, "kms_dri") == 0) {
286 sdev->ws = sdev->dd->winsys[i].create_winsys_kms_dri(sdev->fd);
287 break;
288 }
289 }
290 if (!sdev->ws)
291 goto fail;
292
293 *devs = &sdev->base;
294 return true;
295
296 fail:
297 pipe_loader_sw_probe_teardown_common(sdev);
298 if (sdev->fd != -1)
299 close(sdev->fd);
300 FREE(sdev);
301 return false;
302 }
303 #endif
304
305 bool
pipe_loader_sw_probe_null(struct pipe_loader_device ** devs)306 pipe_loader_sw_probe_null(struct pipe_loader_device **devs)
307 {
308 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
309 int i;
310
311 if (!sdev)
312 return false;
313
314 if (!pipe_loader_sw_probe_init_common(sdev))
315 goto fail;
316
317 for (i = 0; sdev->dd->winsys[i].name; i++) {
318 if (strcmp(sdev->dd->winsys[i].name, "null") == 0) {
319 sdev->ws = sdev->dd->winsys[i].create_winsys();
320 break;
321 }
322 }
323 if (!sdev->ws)
324 goto fail;
325
326 *devs = &sdev->base;
327 return true;
328
329 fail:
330 pipe_loader_sw_probe_teardown_common(sdev);
331 FREE(sdev);
332 return false;
333 }
334
335 int
pipe_loader_sw_probe(struct pipe_loader_device ** devs,int ndev)336 pipe_loader_sw_probe(struct pipe_loader_device **devs, int ndev)
337 {
338 int i = 1;
339
340 if (i <= ndev) {
341 if (!pipe_loader_sw_probe_null(devs)) {
342 i--;
343 }
344 }
345
346 return i;
347 }
348
349 bool
pipe_loader_sw_probe_wrapped(struct pipe_loader_device ** dev,struct pipe_screen * screen)350 pipe_loader_sw_probe_wrapped(struct pipe_loader_device **dev,
351 struct pipe_screen *screen)
352 {
353 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
354 int i;
355
356 if (!sdev)
357 return false;
358
359 if (!pipe_loader_sw_probe_init_common(sdev))
360 goto fail;
361
362 for (i = 0; sdev->dd->winsys[i].name; i++) {
363 if (strcmp(sdev->dd->winsys[i].name, "wrapped") == 0) {
364 sdev->ws = sdev->dd->winsys[i].create_winsys_wrapped(screen);
365 break;
366 }
367 }
368 if (!sdev->ws)
369 goto fail;
370
371 *dev = &sdev->base;
372 return true;
373
374 fail:
375 pipe_loader_sw_probe_teardown_common(sdev);
376 FREE(sdev);
377 return false;
378 }
379
380 static void
pipe_loader_sw_release(struct pipe_loader_device ** dev)381 pipe_loader_sw_release(struct pipe_loader_device **dev)
382 {
383 UNUSED struct pipe_loader_sw_device *sdev =
384 pipe_loader_sw_device(*dev);
385
386 sdev->ws->destroy(sdev->ws);
387 #ifndef GALLIUM_STATIC_TARGETS
388 if (sdev->lib)
389 util_dl_close(sdev->lib);
390 #endif
391
392 #ifdef HAVE_DRISW_KMS
393 if (sdev->fd != -1)
394 close(sdev->fd);
395 #endif
396
397 pipe_loader_base_release(dev);
398 }
399
400 static const struct driOptionDescription *
pipe_loader_sw_get_driconf(struct pipe_loader_device * dev,unsigned * count)401 pipe_loader_sw_get_driconf(struct pipe_loader_device *dev, unsigned *count)
402 {
403 *count = 0;
404 return NULL;
405 }
406
407 #if defined(HAVE_DRI) && defined(HAVE_ZINK)
408 static const driOptionDescription zink_driconf[] = {
409 #include "gallium/drivers/zink/driinfo_zink.h"
410 };
411
412 static const struct driOptionDescription *
pipe_loader_vk_get_driconf(struct pipe_loader_device * dev,unsigned * count)413 pipe_loader_vk_get_driconf(struct pipe_loader_device *dev, unsigned *count)
414 {
415 *count = ARRAY_SIZE(zink_driconf);
416 return zink_driconf;
417 }
418 #endif
419
420 static struct pipe_screen *
pipe_loader_sw_create_screen(struct pipe_loader_device * dev,const struct pipe_screen_config * config,bool sw_vk)421 pipe_loader_sw_create_screen(struct pipe_loader_device *dev,
422 const struct pipe_screen_config *config, bool sw_vk)
423 {
424 struct pipe_loader_sw_device *sdev = pipe_loader_sw_device(dev);
425 struct pipe_screen *screen;
426
427 screen = sdev->dd->create_screen(sdev->ws, config, sw_vk);
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