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_PIPE_LOADER_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
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
62#ifdef GALLIUM_STATIC_TARGETS
63static const struct sw_driver_descriptor driver_descriptors = {
64   .create_screen = sw_screen_create_vk,
65   .winsys = {
66#ifdef HAVE_PIPE_LOADER_DRI
67      {
68         .name = "dri",
69         .create_winsys = dri_create_sw_winsys,
70      },
71#endif
72#ifdef HAVE_PIPE_LOADER_KMS
73      {
74         .name = "kms_dri",
75         .create_winsys = kms_dri_create_winsys,
76      },
77#endif
78#ifndef __ANDROID__
79      {
80         .name = "null",
81         .create_winsys = null_sw_create,
82      },
83      {
84         .name = "wrapped",
85         .create_winsys = wrapper_sw_winsys_wrap_pipe_screen,
86      },
87#endif
88      { 0 },
89   }
90};
91#endif
92
93static bool
94pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device *sdev)
95{
96   sdev->base.type = PIPE_LOADER_DEVICE_SOFTWARE;
97   sdev->base.driver_name = "swrast";
98   sdev->base.ops = &pipe_loader_sw_ops;
99   sdev->fd = -1;
100
101#ifdef GALLIUM_STATIC_TARGETS
102   sdev->dd = &driver_descriptors;
103   if (!sdev->dd)
104      return false;
105#else
106   const char *search_dir = getenv("GALLIUM_PIPE_SEARCH_DIR");
107   if (search_dir == NULL)
108      search_dir = PIPE_SEARCH_DIR;
109
110   sdev->lib = pipe_loader_find_module("swrast", search_dir);
111   if (!sdev->lib)
112      return false;
113
114   sdev->dd = (const struct sw_driver_descriptor *)
115      util_dl_get_proc_address(sdev->lib, "swrast_driver_descriptor");
116
117   if (!sdev->dd){
118      util_dl_close(sdev->lib);
119      sdev->lib = NULL;
120      return false;
121   }
122#endif
123
124   return true;
125}
126
127static void
128pipe_loader_sw_probe_teardown_common(struct pipe_loader_sw_device *sdev)
129{
130#ifndef GALLIUM_STATIC_TARGETS
131   if (sdev->lib)
132      util_dl_close(sdev->lib);
133#endif
134}
135
136#ifdef HAVE_PIPE_LOADER_DRI
137bool
138pipe_loader_sw_probe_dri(struct pipe_loader_device **devs, const struct drisw_loader_funcs *drisw_lf)
139{
140   struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
141   int i;
142
143   if (!sdev)
144      return false;
145
146   if (!pipe_loader_sw_probe_init_common(sdev))
147      goto fail;
148
149   for (i = 0; sdev->dd->winsys[i].name; i++) {
150      if (strcmp(sdev->dd->winsys[i].name, "dri") == 0) {
151         sdev->ws = sdev->dd->winsys[i].create_winsys(drisw_lf);
152         break;
153      }
154   }
155   if (!sdev->ws)
156      goto fail;
157
158   *devs = &sdev->base;
159   return true;
160
161fail:
162   pipe_loader_sw_probe_teardown_common(sdev);
163   FREE(sdev);
164   return false;
165}
166#endif
167
168#ifdef HAVE_PIPE_LOADER_KMS
169bool
170pipe_loader_sw_probe_kms(struct pipe_loader_device **devs, int fd)
171{
172   struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
173   int i;
174
175   if (!sdev)
176      return false;
177
178   if (!pipe_loader_sw_probe_init_common(sdev))
179      goto fail;
180
181   if (fd < 0 || (sdev->fd = os_dupfd_cloexec(fd)) < 0)
182      goto fail;
183
184   for (i = 0; sdev->dd->winsys[i].name; i++) {
185      if (strcmp(sdev->dd->winsys[i].name, "kms_dri") == 0) {
186         sdev->ws = sdev->dd->winsys[i].create_winsys(sdev->fd);
187         break;
188      }
189   }
190   if (!sdev->ws)
191      goto fail;
192
193   *devs = &sdev->base;
194   return true;
195
196fail:
197   pipe_loader_sw_probe_teardown_common(sdev);
198   if (sdev->fd != -1)
199      close(sdev->fd);
200   FREE(sdev);
201   return false;
202}
203#endif
204
205bool
206pipe_loader_sw_probe_null(struct pipe_loader_device **devs)
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, "null") == 0) {
219         sdev->ws = sdev->dd->winsys[i].create_winsys();
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
235int
236pipe_loader_sw_probe(struct pipe_loader_device **devs, int ndev)
237{
238   int i = 1;
239
240   if (i <= ndev) {
241      if (!pipe_loader_sw_probe_null(devs)) {
242         i--;
243      }
244   }
245
246   return i;
247}
248
249boolean
250pipe_loader_sw_probe_wrapped(struct pipe_loader_device **dev,
251                             struct pipe_screen *screen)
252{
253   struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
254   int i;
255
256   if (!sdev)
257      return false;
258
259   if (!pipe_loader_sw_probe_init_common(sdev))
260      goto fail;
261
262   for (i = 0; sdev->dd->winsys[i].name; i++) {
263      if (strcmp(sdev->dd->winsys[i].name, "wrapped") == 0) {
264         sdev->ws = sdev->dd->winsys[i].create_winsys(screen);
265         break;
266      }
267   }
268   if (!sdev->ws)
269      goto fail;
270
271   *dev = &sdev->base;
272   return true;
273
274fail:
275   pipe_loader_sw_probe_teardown_common(sdev);
276   FREE(sdev);
277   return false;
278}
279
280static void
281pipe_loader_sw_release(struct pipe_loader_device **dev)
282{
283   UNUSED struct pipe_loader_sw_device *sdev =
284      pipe_loader_sw_device(*dev);
285
286#ifndef GALLIUM_STATIC_TARGETS
287   if (sdev->lib)
288      util_dl_close(sdev->lib);
289#endif
290
291#ifdef HAVE_PIPE_LOADER_KMS
292   if (sdev->fd != -1)
293      close(sdev->fd);
294#endif
295
296   pipe_loader_base_release(dev);
297}
298
299static const struct driOptionDescription *
300pipe_loader_sw_get_driconf(struct pipe_loader_device *dev, unsigned *count)
301{
302   *count = 0;
303   return NULL;
304}
305
306static struct pipe_screen *
307pipe_loader_sw_create_screen(struct pipe_loader_device *dev,
308                             const struct pipe_screen_config *config, bool sw_vk)
309{
310   struct pipe_loader_sw_device *sdev = pipe_loader_sw_device(dev);
311   struct pipe_screen *screen;
312
313   screen = sdev->dd->create_screen(sdev->ws, sw_vk);
314   if (!screen)
315      sdev->ws->destroy(sdev->ws);
316
317   return screen ? debug_screen_wrap(screen) : NULL;
318}
319
320static const struct pipe_loader_ops pipe_loader_sw_ops = {
321   .create_screen = pipe_loader_sw_create_screen,
322   .get_driconf = pipe_loader_sw_get_driconf,
323   .release = pipe_loader_sw_release
324};
325