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_DRISW_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#include "util/driconf.h" 47 48struct 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 60static const struct pipe_loader_ops pipe_loader_sw_ops; 61#if defined(HAVE_DRI) && defined(HAVE_ZINK) 62static const struct pipe_loader_ops pipe_loader_vk_ops; 63#endif 64 65#ifdef GALLIUM_STATIC_TARGETS 66static const struct sw_driver_descriptor driver_descriptors = { 67 .create_screen = sw_screen_create_vk, 68 .winsys = { 69#ifdef HAVE_DRI 70 { 71 .name = "dri", 72 .create_winsys = dri_create_sw_winsys, 73 }, 74#endif 75#ifdef HAVE_DRISW_KMS 76 { 77 .name = "kms_dri", 78 .create_winsys = kms_dri_create_winsys, 79 }, 80#endif 81#ifndef __ANDROID__ 82 { 83 .name = "null", 84 .create_winsys = null_sw_create, 85 }, 86 { 87 .name = "wrapped", 88 .create_winsys = wrapper_sw_winsys_wrap_pipe_screen, 89 }, 90#endif 91 { 0 }, 92 } 93}; 94#endif 95 96#if defined(GALLIUM_STATIC_TARGETS) && defined(HAVE_ZINK) && defined(HAVE_DRI) 97static const struct sw_driver_descriptor kopper_driver_descriptors = { 98 .create_screen = sw_screen_create_zink, 99 .winsys = { 100 { 101 .name = "dri", 102 .create_winsys = dri_create_sw_winsys, 103 }, 104#ifdef HAVE_DRISW_KMS 105 { 106 .name = "kms_dri", 107 .create_winsys = kms_dri_create_winsys, 108 }, 109#endif 110#ifndef __ANDROID__ 111 { 112 .name = "null", 113 .create_winsys = null_sw_create, 114 }, 115 { 116 .name = "wrapped", 117 .create_winsys = wrapper_sw_winsys_wrap_pipe_screen, 118 }, 119#endif 120 { 0 }, 121 } 122}; 123#endif 124 125static bool 126pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device *sdev) 127{ 128 sdev->base.type = PIPE_LOADER_DEVICE_SOFTWARE; 129 sdev->base.driver_name = "swrast"; 130 sdev->base.ops = &pipe_loader_sw_ops; 131 sdev->fd = -1; 132 133#ifdef GALLIUM_STATIC_TARGETS 134 sdev->dd = &driver_descriptors; 135 if (!sdev->dd) 136 return false; 137#else 138 const char *search_dir = getenv("GALLIUM_PIPE_SEARCH_DIR"); 139 if (search_dir == NULL) 140 search_dir = PIPE_SEARCH_DIR; 141 142 sdev->lib = pipe_loader_find_module("swrast", search_dir); 143 if (!sdev->lib) 144 return false; 145 146 sdev->dd = (const struct sw_driver_descriptor *) 147 util_dl_get_proc_address(sdev->lib, "swrast_driver_descriptor"); 148 149 if (!sdev->dd){ 150 util_dl_close(sdev->lib); 151 sdev->lib = NULL; 152 return false; 153 } 154#endif 155 156 return true; 157} 158 159#if defined(HAVE_DRI) && defined(HAVE_ZINK) 160static bool 161pipe_loader_vk_probe_init_common(struct pipe_loader_sw_device *sdev) 162{ 163 sdev->base.type = PIPE_LOADER_DEVICE_PLATFORM; 164 sdev->base.driver_name = "kopper"; 165 sdev->base.ops = &pipe_loader_vk_ops; 166 sdev->fd = -1; 167 168#ifdef GALLIUM_STATIC_TARGETS 169 sdev->dd = &kopper_driver_descriptors; 170 if (!sdev->dd) 171 return false; 172#else 173 const char *search_dir = getenv("GALLIUM_PIPE_SEARCH_DIR"); 174 if (search_dir == NULL) 175 search_dir = PIPE_SEARCH_DIR; 176 177 sdev->lib = pipe_loader_find_module("swrast", search_dir); 178 if (!sdev->lib) 179 return false; 180 181 sdev->dd = (const struct sw_driver_descriptor *) 182 util_dl_get_proc_address(sdev->lib, "swrast_driver_descriptor"); 183 184 if (!sdev->dd){ 185 util_dl_close(sdev->lib); 186 sdev->lib = NULL; 187 return false; 188 } 189#endif 190 191 return true; 192} 193#endif 194 195static void 196pipe_loader_sw_probe_teardown_common(struct pipe_loader_sw_device *sdev) 197{ 198#ifndef GALLIUM_STATIC_TARGETS 199 if (sdev->lib) 200 util_dl_close(sdev->lib); 201#endif 202} 203 204#ifdef HAVE_DRI 205bool 206pipe_loader_sw_probe_dri(struct pipe_loader_device **devs, const struct drisw_loader_funcs *drisw_lf) 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, "dri") == 0) { 219 sdev->ws = sdev->dd->winsys[i].create_winsys(drisw_lf); 220 break; 221 } 222 } 223 if (!sdev->ws) 224 goto fail; 225 226 *devs = &sdev->base; 227 return true; 228 229fail: 230 pipe_loader_sw_probe_teardown_common(sdev); 231 FREE(sdev); 232 return false; 233} 234#ifdef HAVE_ZINK 235bool 236pipe_loader_vk_probe_dri(struct pipe_loader_device **devs, const struct drisw_loader_funcs *drisw_lf) 237{ 238 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device); 239 int i; 240 241 if (!sdev) 242 return false; 243 244 if (!pipe_loader_vk_probe_init_common(sdev)) 245 goto fail; 246 247 for (i = 0; sdev->dd->winsys[i].name; i++) { 248 if (strcmp(sdev->dd->winsys[i].name, "dri") == 0) { 249 sdev->ws = sdev->dd->winsys[i].create_winsys(drisw_lf); 250 break; 251 } 252 } 253 if (!sdev->ws) 254 goto fail; 255 256 *devs = &sdev->base; 257 return true; 258 259fail: 260 pipe_loader_sw_probe_teardown_common(sdev); 261 FREE(sdev); 262 return false; 263} 264#endif 265#endif 266 267#ifdef HAVE_DRISW_KMS 268bool 269pipe_loader_sw_probe_kms(struct pipe_loader_device **devs, int fd) 270{ 271 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device); 272 int i; 273 274 if (!sdev) 275 return false; 276 277 if (!pipe_loader_sw_probe_init_common(sdev)) 278 goto fail; 279 280 if (fd < 0 || (sdev->fd = os_dupfd_cloexec(fd)) < 0) 281 goto fail; 282 283 for (i = 0; sdev->dd->winsys[i].name; i++) { 284 if (strcmp(sdev->dd->winsys[i].name, "kms_dri") == 0) { 285 sdev->ws = sdev->dd->winsys[i].create_winsys(sdev->fd); 286 break; 287 } 288 } 289 if (!sdev->ws) 290 goto fail; 291 292 *devs = &sdev->base; 293 return true; 294 295fail: 296 pipe_loader_sw_probe_teardown_common(sdev); 297 if (sdev->fd != -1) 298 close(sdev->fd); 299 FREE(sdev); 300 return false; 301} 302#endif 303 304bool 305pipe_loader_sw_probe_null(struct pipe_loader_device **devs) 306{ 307 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device); 308 int i; 309 310 if (!sdev) 311 return false; 312 313 if (!pipe_loader_sw_probe_init_common(sdev)) 314 goto fail; 315 316 for (i = 0; sdev->dd->winsys[i].name; i++) { 317 if (strcmp(sdev->dd->winsys[i].name, "null") == 0) { 318 sdev->ws = sdev->dd->winsys[i].create_winsys(); 319 break; 320 } 321 } 322 if (!sdev->ws) 323 goto fail; 324 325 *devs = &sdev->base; 326 return true; 327 328fail: 329 pipe_loader_sw_probe_teardown_common(sdev); 330 FREE(sdev); 331 return false; 332} 333 334int 335pipe_loader_sw_probe(struct pipe_loader_device **devs, int ndev) 336{ 337 int i = 1; 338 339 if (i <= ndev) { 340 if (!pipe_loader_sw_probe_null(devs)) { 341 i--; 342 } 343 } 344 345 return i; 346} 347 348boolean 349pipe_loader_sw_probe_wrapped(struct pipe_loader_device **dev, 350 struct pipe_screen *screen) 351{ 352 struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device); 353 int i; 354 355 if (!sdev) 356 return false; 357 358 if (!pipe_loader_sw_probe_init_common(sdev)) 359 goto fail; 360 361 for (i = 0; sdev->dd->winsys[i].name; i++) { 362 if (strcmp(sdev->dd->winsys[i].name, "wrapped") == 0) { 363 sdev->ws = sdev->dd->winsys[i].create_winsys(screen); 364 break; 365 } 366 } 367 if (!sdev->ws) 368 goto fail; 369 370 *dev = &sdev->base; 371 return true; 372 373fail: 374 pipe_loader_sw_probe_teardown_common(sdev); 375 FREE(sdev); 376 return false; 377} 378 379static void 380pipe_loader_sw_release(struct pipe_loader_device **dev) 381{ 382 UNUSED struct pipe_loader_sw_device *sdev = 383 pipe_loader_sw_device(*dev); 384 385#ifndef GALLIUM_STATIC_TARGETS 386 if (sdev->lib) 387 util_dl_close(sdev->lib); 388#endif 389 390#ifdef HAVE_DRISW_KMS 391 if (sdev->fd != -1) 392 close(sdev->fd); 393#endif 394 395 pipe_loader_base_release(dev); 396} 397 398static const struct driOptionDescription * 399pipe_loader_sw_get_driconf(struct pipe_loader_device *dev, unsigned *count) 400{ 401 *count = 0; 402 return NULL; 403} 404 405#if defined(HAVE_DRI) && defined(HAVE_ZINK) 406static const driOptionDescription zink_driconf[] = { 407 #include "gallium/drivers/zink/driinfo_zink.h" 408}; 409 410static const struct driOptionDescription * 411pipe_loader_vk_get_driconf(struct pipe_loader_device *dev, unsigned *count) 412{ 413 *count = ARRAY_SIZE(zink_driconf); 414 return zink_driconf; 415} 416#endif 417 418static struct pipe_screen * 419pipe_loader_sw_create_screen(struct pipe_loader_device *dev, 420 const struct pipe_screen_config *config, bool sw_vk) 421{ 422 struct pipe_loader_sw_device *sdev = pipe_loader_sw_device(dev); 423 struct pipe_screen *screen; 424 425 screen = sdev->dd->create_screen(sdev->ws, config, sw_vk); 426 if (!screen) 427 sdev->ws->destroy(sdev->ws); 428 429 return screen ? debug_screen_wrap(screen) : NULL; 430} 431 432static const struct pipe_loader_ops pipe_loader_sw_ops = { 433 .create_screen = pipe_loader_sw_create_screen, 434 .get_driconf = pipe_loader_sw_get_driconf, 435 .release = pipe_loader_sw_release 436}; 437 438#if defined(HAVE_DRI) && defined(HAVE_ZINK) 439static const struct pipe_loader_ops pipe_loader_vk_ops = { 440 .create_screen = pipe_loader_sw_create_screen, 441 .get_driconf = pipe_loader_vk_get_driconf, 442 .release = pipe_loader_sw_release 443}; 444#endif 445