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