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