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