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/u_memory.h"
35#include "util/u_dl.h"
36#include "sw/dri/dri_sw_winsys.h"
37#include "sw/kms-dri/kms_dri_sw_winsys.h"
38#include "sw/null/null_sw_winsys.h"
39#include "sw/wrapper/wrapper_sw_winsys.h"
40#include "target-helpers/sw_helper_public.h"
41#include "state_tracker/drisw_api.h"
42#include "state_tracker/sw_driver.h"
43#include "state_tracker/sw_winsys.h"
44
45struct pipe_loader_sw_device {
46   struct pipe_loader_device base;
47   const struct sw_driver_descriptor *dd;
48#ifndef GALLIUM_STATIC_TARGETS
49   struct util_dl_library *lib;
50#endif
51   struct sw_winsys *ws;
52   int fd;
53};
54
55#define pipe_loader_sw_device(dev) ((struct pipe_loader_sw_device *)dev)
56
57static const struct pipe_loader_ops pipe_loader_sw_ops;
58
59#ifdef GALLIUM_STATIC_TARGETS
60static const struct sw_driver_descriptor driver_descriptors = {
61   .create_screen = sw_screen_create,
62   .winsys = {
63#ifdef HAVE_PIPE_LOADER_DRI
64      {
65         .name = "dri",
66         .create_winsys = dri_create_sw_winsys,
67      },
68#endif
69#ifdef HAVE_PIPE_LOADER_KMS
70      {
71         .name = "kms_dri",
72         .create_winsys = kms_dri_create_winsys,
73      },
74#endif
75/**
76 * XXX: Do not include these two for non autotools builds.
77 * They don't have neither opencl nor nine, where these are used.
78 */
79#ifndef DROP_PIPE_LOADER_MISC
80      {
81         .name = "null",
82         .create_winsys = null_sw_create,
83      },
84      {
85         .name = "wrapped",
86         .create_winsys = wrapper_sw_winsys_wrap_pipe_screen,
87      },
88#endif
89      { 0 },
90   }
91};
92#endif
93
94static bool
95pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device *sdev)
96{
97   sdev->base.type = PIPE_LOADER_DEVICE_SOFTWARE;
98   sdev->base.driver_name = "swrast";
99   sdev->base.ops = &pipe_loader_sw_ops;
100   sdev->fd = -1;
101
102#ifdef GALLIUM_STATIC_TARGETS
103   sdev->dd = &driver_descriptors;
104   if (!sdev->dd)
105      return false;
106#else
107   sdev->lib = pipe_loader_find_module("swrast", PIPE_SEARCH_DIR);
108   if (!sdev->lib)
109      return false;
110
111   sdev->dd = (const struct sw_driver_descriptor *)
112      util_dl_get_proc_address(sdev->lib, "swrast_driver_descriptor");
113
114   if (!sdev->dd){
115      util_dl_close(sdev->lib);
116      sdev->lib = NULL;
117      return false;
118   }
119#endif
120
121   return true;
122}
123
124static void
125pipe_loader_sw_probe_teardown_common(struct pipe_loader_sw_device *sdev)
126{
127#ifndef GALLIUM_STATIC_TARGETS
128   if (sdev->lib)
129      util_dl_close(sdev->lib);
130#endif
131}
132
133#ifdef HAVE_PIPE_LOADER_DRI
134bool
135pipe_loader_sw_probe_dri(struct pipe_loader_device **devs, const struct drisw_loader_funcs *drisw_lf)
136{
137   struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
138   int i;
139
140   if (!sdev)
141      return false;
142
143   if (!pipe_loader_sw_probe_init_common(sdev))
144      goto fail;
145
146   for (i = 0; sdev->dd->winsys[i].name; i++) {
147      if (strcmp(sdev->dd->winsys[i].name, "dri") == 0) {
148         sdev->ws = sdev->dd->winsys[i].create_winsys(drisw_lf);
149         break;
150      }
151   }
152   if (!sdev->ws)
153      goto fail;
154
155   *devs = &sdev->base;
156   return true;
157
158fail:
159   pipe_loader_sw_probe_teardown_common(sdev);
160   FREE(sdev);
161   return false;
162}
163#endif
164
165#ifdef HAVE_PIPE_LOADER_KMS
166bool
167pipe_loader_sw_probe_kms(struct pipe_loader_device **devs, int fd)
168{
169   struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
170   int i;
171
172   if (!sdev)
173      return false;
174
175   if (!pipe_loader_sw_probe_init_common(sdev))
176      goto fail;
177
178   if (fd < 0 || (sdev->fd = fcntl(fd, F_DUPFD_CLOEXEC, 3)) < 0)
179      goto fail;
180
181   for (i = 0; sdev->dd->winsys[i].name; i++) {
182      if (strcmp(sdev->dd->winsys[i].name, "kms_dri") == 0) {
183         sdev->ws = sdev->dd->winsys[i].create_winsys(sdev->fd);
184         break;
185      }
186   }
187   if (!sdev->ws)
188      goto fail;
189
190   *devs = &sdev->base;
191   return true;
192
193fail:
194   pipe_loader_sw_probe_teardown_common(sdev);
195   if (sdev->fd != -1)
196      close(sdev->fd);
197   FREE(sdev);
198   return false;
199}
200#endif
201
202bool
203pipe_loader_sw_probe_null(struct pipe_loader_device **devs)
204{
205   struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
206   int i;
207
208   if (!sdev)
209      return false;
210
211   if (!pipe_loader_sw_probe_init_common(sdev))
212      goto fail;
213
214   for (i = 0; sdev->dd->winsys[i].name; i++) {
215      if (strcmp(sdev->dd->winsys[i].name, "null") == 0) {
216         sdev->ws = sdev->dd->winsys[i].create_winsys();
217         break;
218      }
219   }
220   if (!sdev->ws)
221      goto fail;
222
223   *devs = &sdev->base;
224   return true;
225
226fail:
227   pipe_loader_sw_probe_teardown_common(sdev);
228   FREE(sdev);
229   return false;
230}
231
232int
233pipe_loader_sw_probe(struct pipe_loader_device **devs, int ndev)
234{
235   int i = 1;
236
237   if (i <= ndev) {
238      if (!pipe_loader_sw_probe_null(devs)) {
239         i--;
240      }
241   }
242
243   return i;
244}
245
246boolean
247pipe_loader_sw_probe_wrapped(struct pipe_loader_device **dev,
248                             struct pipe_screen *screen)
249{
250   struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device);
251   int i;
252
253   if (!sdev)
254      return false;
255
256   if (!pipe_loader_sw_probe_init_common(sdev))
257      goto fail;
258
259   for (i = 0; sdev->dd->winsys[i].name; i++) {
260      if (strcmp(sdev->dd->winsys[i].name, "wrapped") == 0) {
261         sdev->ws = sdev->dd->winsys[i].create_winsys(screen);
262         break;
263      }
264   }
265   if (!sdev->ws)
266      goto fail;
267
268   *dev = &sdev->base;
269   return true;
270
271fail:
272   pipe_loader_sw_probe_teardown_common(sdev);
273   FREE(sdev);
274   return false;
275}
276
277static void
278pipe_loader_sw_release(struct pipe_loader_device **dev)
279{
280   MAYBE_UNUSED struct pipe_loader_sw_device *sdev =
281      pipe_loader_sw_device(*dev);
282
283#ifndef GALLIUM_STATIC_TARGETS
284   if (sdev->lib)
285      util_dl_close(sdev->lib);
286#endif
287
288#ifdef HAVE_PIPE_LOADER_KMS
289   if (sdev->fd != -1)
290      close(sdev->fd);
291#endif
292
293   pipe_loader_base_release(dev);
294}
295
296static const char *
297pipe_loader_sw_get_driconf_xml(struct pipe_loader_device *dev)
298{
299   return NULL;
300}
301
302static struct pipe_screen *
303pipe_loader_sw_create_screen(struct pipe_loader_device *dev,
304                             const struct pipe_screen_config *config)
305{
306   struct pipe_loader_sw_device *sdev = pipe_loader_sw_device(dev);
307   struct pipe_screen *screen;
308
309   screen = sdev->dd->create_screen(sdev->ws);
310   if (!screen)
311      sdev->ws->destroy(sdev->ws);
312
313   return screen;
314}
315
316static const struct pipe_loader_ops pipe_loader_sw_ops = {
317   .create_screen = pipe_loader_sw_create_screen,
318   .get_driconf_xml = pipe_loader_sw_get_driconf_xml,
319   .release = pipe_loader_sw_release
320};
321