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