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
48struct 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
60static const struct pipe_loader_ops pipe_loader_sw_ops;
61#if defined(HAVE_DRI) && defined(HAVE_ZINK)
62static const struct pipe_loader_ops pipe_loader_vk_ops;
63#endif
64
65#ifdef GALLIUM_STATIC_TARGETS
66static 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)
97static 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
125static bool
126pipe_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)
160static bool
161pipe_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
195static void
196pipe_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
205bool
206pipe_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
229fail:
230   pipe_loader_sw_probe_teardown_common(sdev);
231   FREE(sdev);
232   return false;
233}
234#ifdef HAVE_ZINK
235bool
236pipe_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
259fail:
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
268bool
269pipe_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
295fail:
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
304bool
305pipe_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
328fail:
329   pipe_loader_sw_probe_teardown_common(sdev);
330   FREE(sdev);
331   return false;
332}
333
334int
335pipe_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
348boolean
349pipe_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
373fail:
374   pipe_loader_sw_probe_teardown_common(sdev);
375   FREE(sdev);
376   return false;
377}
378
379static void
380pipe_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
398static const struct driOptionDescription *
399pipe_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)
406static const driOptionDescription zink_driconf[] = {
407      #include "gallium/drivers/zink/driinfo_zink.h"
408};
409
410static const struct driOptionDescription *
411pipe_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
418static struct pipe_screen *
419pipe_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
432static 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)
439static 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