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 
48 struct 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 
60 static const struct pipe_loader_ops pipe_loader_sw_ops;
61 
62 #ifdef GALLIUM_STATIC_TARGETS
63 static 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 
93 static bool
pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device * sdev)94 pipe_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 
127 static void
pipe_loader_sw_probe_teardown_common(struct pipe_loader_sw_device * sdev)128 pipe_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
137 bool
pipe_loader_sw_probe_dri(struct pipe_loader_device ** devs,const struct drisw_loader_funcs * drisw_lf)138 pipe_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 
161 fail:
162    pipe_loader_sw_probe_teardown_common(sdev);
163    FREE(sdev);
164    return false;
165 }
166 #endif
167 
168 #ifdef HAVE_PIPE_LOADER_KMS
169 bool
pipe_loader_sw_probe_kms(struct pipe_loader_device ** devs,int fd)170 pipe_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 
196 fail:
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 
205 bool
pipe_loader_sw_probe_null(struct pipe_loader_device ** devs)206 pipe_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 
229 fail:
230    pipe_loader_sw_probe_teardown_common(sdev);
231    FREE(sdev);
232    return false;
233 }
234 
235 int
pipe_loader_sw_probe(struct pipe_loader_device ** devs,int ndev)236 pipe_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 
249 boolean
pipe_loader_sw_probe_wrapped(struct pipe_loader_device ** dev,struct pipe_screen * screen)250 pipe_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 
274 fail:
275    pipe_loader_sw_probe_teardown_common(sdev);
276    FREE(sdev);
277    return false;
278 }
279 
280 static void
pipe_loader_sw_release(struct pipe_loader_device ** dev)281 pipe_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 
299 static const struct driOptionDescription *
pipe_loader_sw_get_driconf(struct pipe_loader_device * dev,unsigned * count)300 pipe_loader_sw_get_driconf(struct pipe_loader_device *dev, unsigned *count)
301 {
302    *count = 0;
303    return NULL;
304 }
305 
306 static struct pipe_screen *
pipe_loader_sw_create_screen(struct pipe_loader_device * dev,const struct pipe_screen_config * config,bool sw_vk)307 pipe_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 
320 static 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