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#include "pipe_loader_priv.h" 29 30#include "util/u_cpu_detect.h" 31#include "util/u_inlines.h" 32#include "util/u_memory.h" 33#include "util/u_string.h" 34#include "util/u_dl.h" 35#include "util/u_file.h" 36#include "util/xmlconfig.h" 37#include "util/driconf.h" 38 39#include <string.h> 40 41#ifdef _MSC_VER 42#include <stdlib.h> 43#define PATH_MAX _MAX_PATH 44#endif 45 46#define MODULE_PREFIX "pipe_" 47 48static int (*backends[])(struct pipe_loader_device **, int) = { 49#ifdef HAVE_LIBDRM 50 &pipe_loader_drm_probe, 51#endif 52 &pipe_loader_sw_probe 53}; 54 55const driOptionDescription gallium_driconf[] = { 56#include "driinfo_gallium.h" 57}; 58 59int 60pipe_loader_probe(struct pipe_loader_device **devs, int ndev) 61{ 62 int i, n = 0; 63 64 for (i = 0; i < ARRAY_SIZE(backends); i++) 65 n += backends[i](&devs[n], MAX2(0, ndev - n)); 66 67 return n; 68} 69 70void 71pipe_loader_release(struct pipe_loader_device **devs, int ndev) 72{ 73 int i; 74 75 for (i = 0; i < ndev; i++) 76 devs[i]->ops->release(&devs[i]); 77} 78 79void 80pipe_loader_base_release(struct pipe_loader_device **dev) 81{ 82 driDestroyOptionCache(&(*dev)->option_cache); 83 driDestroyOptionInfo(&(*dev)->option_info); 84 85 FREE(*dev); 86 *dev = NULL; 87} 88 89static driOptionDescription * 90merge_driconf(const driOptionDescription *driver_driconf, unsigned driver_count, 91 unsigned *merged_count) 92{ 93 unsigned gallium_count = ARRAY_SIZE(gallium_driconf); 94 driOptionDescription *merged = malloc((driver_count + gallium_count) * 95 sizeof(*merged)); 96 if (!merged) { 97 *merged_count = 0; 98 return NULL; 99 } 100 101 memcpy(merged, gallium_driconf, sizeof(*merged) * gallium_count); 102 memcpy(&merged[gallium_count], driver_driconf, sizeof(*merged) * driver_count); 103 104 *merged_count = driver_count + gallium_count; 105 return merged; 106} 107 108/** 109 * Ensure that dev->option_cache is initialized appropriately for the driver. 110 * 111 * This function can be called multiple times. 112 * 113 * \param dev Device for which options should be loaded. 114 */ 115static void 116pipe_loader_load_options(struct pipe_loader_device *dev) 117{ 118 if (dev->option_info.info) 119 return; 120 121 unsigned driver_count, merged_count; 122 const driOptionDescription *driver_driconf = 123 dev->ops->get_driconf(dev, &driver_count); 124 125 const driOptionDescription *merged_driconf = 126 merge_driconf(driver_driconf, driver_count, &merged_count); 127 driParseOptionInfo(&dev->option_info, merged_driconf, merged_count); 128 free((void *)merged_driconf); 129} 130 131void 132pipe_loader_config_options(struct pipe_loader_device *dev) 133{ 134 if (!dev->option_cache.info) { 135 driParseConfigFiles(&dev->option_cache, &dev->option_info, 0, 136 dev->driver_name, NULL, NULL, NULL, 0, NULL, 0); 137 } 138} 139 140char * 141pipe_loader_get_driinfo_xml(const char *driver_name) 142{ 143 unsigned driver_count = 0; 144 const driOptionDescription *driver_driconf = NULL; 145 146#ifdef HAVE_LIBDRM 147 driver_driconf = pipe_loader_drm_get_driconf_by_name(driver_name, 148 &driver_count); 149#endif 150 151 unsigned merged_count; 152 const driOptionDescription *merged_driconf = 153 merge_driconf(driver_driconf, driver_count, &merged_count); 154 free((void *)driver_driconf); 155 156 char *xml = driGetOptionsXml(merged_driconf, merged_count); 157 158 free((void *)merged_driconf); 159 160 return xml; 161} 162 163struct pipe_screen * 164pipe_loader_create_screen_vk(struct pipe_loader_device *dev, bool sw_vk) 165{ 166 struct pipe_screen_config config; 167 168 util_cpu_detect(); 169 pipe_loader_load_options(dev); 170 config.options_info = &dev->option_info; 171 config.options = &dev->option_cache; 172 173 return dev->ops->create_screen(dev, &config, sw_vk); 174} 175 176struct pipe_screen * 177pipe_loader_create_screen(struct pipe_loader_device *dev) 178{ 179 return pipe_loader_create_screen_vk(dev, false); 180} 181 182struct util_dl_library * 183pipe_loader_find_module(const char *driver_name, 184 const char *library_paths) 185{ 186 struct util_dl_library *lib; 187 const char *next; 188 char path[PATH_MAX]; 189 int len, ret; 190 191 for (next = library_paths; *next; library_paths = next + 1) { 192 next = strchrnul(library_paths, ':'); 193 len = next - library_paths; 194 195 if (len) 196 ret = snprintf(path, sizeof(path), "%.*s/%s%s%s", 197 len, library_paths, 198 MODULE_PREFIX, driver_name, UTIL_DL_EXT); 199 else 200 ret = snprintf(path, sizeof(path), "%s%s%s", 201 MODULE_PREFIX, driver_name, UTIL_DL_EXT); 202 203 if (ret > 0 && ret < sizeof(path) && u_file_access(path, 0) != -1) { 204 lib = util_dl_open(path); 205 if (lib) { 206 return lib; 207 } 208 fprintf(stderr, "ERROR: Failed to load pipe driver at `%s': %s\n", 209 path, util_dl_error()); 210 } 211 } 212 213 return NULL; 214} 215