blob: 35ef1e440e6365b3bc4cfcf26d19cf08ba672284 [file] [log] [blame]
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -06001/*
2 * XGL 3-D graphics library
3 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Courtney Goeltzenleuchter <courtney@lunarg.com>
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <assert.h>
35#include <string.h>
36#include <unistd.h>
37#include <fcntl.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <dirent.h>
41#include <errno.h>
42#include <fnmatch.h>
43
44#include <pciaccess.h>
45
46#include <xf86drm.h>
Chia-I Wu155be032014-08-02 09:14:28 +080047#include <i915_drm.h>
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060048
49#include <libudev.h>
50#include <dlfcn.h>
51
52#ifdef HAVE_VALGRIND
53#include <valgrind.h>
54#include <memcheck.h>
55#define VG(x) x
56#else
57#define VG(x)
58#endif
59
60#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s)))
61
62#include "xgl.h"
63#include "xglDbg.h"
64
65#include "driver.h"
66#include "intel_chipset.h"
67#include "gen7_functions.h"
68
69XGL_RESULT XGLAPI GetExtensionSupport(XGL_PHYSICAL_GPU gpu, const XGL_CHAR* pExtName);
70
71
72#if defined(__WIN32__) && !defined(__CYGWIN__)
73#elif defined(__CYGWIN__) && defined(USE_OPENGL32) /* use native windows opengl32 */
74# define ICDENTRY extern
75#elif (defined(__GNUC__) && __GNUC__ >= 4) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
76# define ICDENTRY __attribute__((visibility("default")))
77#endif /* WIN32 && !CYGWIN */
78
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060079/*
80 * Global to contain application allocation call-backs
81 * and GPU enumeration info.
82 */
83struct _xgl_config icd_data;
84
Chia-I Wu3065c9c2014-08-04 06:28:31 +080085static void loader_err(XGL_INT msg_code, const char *msg)
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060086{
Chia-I Wu3065c9c2014-08-04 06:28:31 +080087 icd_log(XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0,
88 XGL_NULL_HANDLE, 0, msg_code, msg);
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060089}
90
91ICDENTRY XGL_RESULT XGLAPI xglLoad()
92{
93 memset(&icd_data, 0, sizeof(icd_data));
94 return XGL_SUCCESS;
95}
96
97ICDENTRY XGL_RESULT XGLAPI xglUnload()
98{
99 // TODO: Free resources
Chia-I Wu3065c9c2014-08-04 06:28:31 +0800100 icd_clear_msg_callbacks();
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600101 return XGL_SUCCESS;
102}
103
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600104static int is_render_node(int fd, struct stat *st)
105{
106 if (fstat(fd, st))
107 return 0;
108
109 if (!S_ISCHR(st->st_mode))
110 return 0;
111
112 return st->st_rdev & 0x80;
113}
114
115static void init_xgl_dispatch_table(struct icd_dispatch_table *pDispatch)
116{
117#define LOAD(xglfunc, driverfunc) do { \
118 pDispatch->xglfunc = driverfunc; \
119} while (0)
120 LOAD(GetGpuInfo, gen7_GetGpuInfo);
121 LOAD(GetExtensionSupport, GetExtensionSupport);
122}
123
124static void init_validation_dispatch_table(struct icd_dispatch_table *pDispatch)
125{
126#define LOAD(xglfunc, driverfunc) do { \
127 pDispatch->xglfunc = driverfunc; \
128} while (0)
129 LOAD(GetGpuInfo, gen7_GetGpuInfo);
130 LOAD(GetExtensionSupport, GetExtensionSupport);
131}
132
133ICDENTRY XGL_RESULT XGLAPI xglInitAndEnumerateGpus(const XGL_APPLICATION_INFO *
134 pAppInfo,
135 const XGL_ALLOC_CALLBACKS *
136 pAllocCb, XGL_UINT maxGpus,
137 XGL_UINT * pGpuCount,
138 XGL_PHYSICAL_GPU * pGpus)
139{
140 struct udev *udev;
141 struct udev_enumerate *e;
142 struct udev_device *device, *parent;
143 struct udev_list_entry *entry;
144 const char *pci_id, *path;
145 const char *usub, *dnode;
146 int fd;
147 struct stat st;
148 char *pci_glob = "*:*";
Chia-I Wu3065c9c2014-08-04 06:28:31 +0800149 XGL_RESULT ret;
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600150 XGL_UINT count = 0;
151 struct _xgl_device *pXglDev;
152
Chia-I Wu3065c9c2014-08-04 06:28:31 +0800153 ret = icd_set_alloc_callbacks(pAllocCb);
154 if (ret != XGL_SUCCESS)
155 return ret;
156
157 ret = XGL_ERROR_UNAVAILABLE;
158
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600159 // TODO: Do we need to keep track of previous calls to xglInitAndEnumerageGpus?
160 /*
161 * xglInitAndEnumerateGpus() can be called multiple times. Calling it more than once
162 * forces driver reinitialization.
163 */
164
165 if (icd_data.num_gpus > 0) {
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600166 // TODO: Free resources and re-initialize
167 }
168 // TODO: Do we need any other validation for incoming pointers?
169
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600170 udev = udev_new();
171 if (udev == NULL) {
172 loader_err(0, "failed to initialize udev context");
173 abort();
174 }
175
176 memset(icd_data.gpu_info, 0,
177 sizeof(icd_data.gpu_info[XGL_MAX_PHYSICAL_GPUS]));
178 memset(icd_data.render_node_list, 0,
179 sizeof(icd_data.render_node_list[XGL_MAX_PHYSICAL_GPUS]));
180
181 fd = -1;
182 e = udev_enumerate_new(udev);
183 udev_enumerate_add_match_subsystem(e, "drm");
184 udev_enumerate_scan_devices(e);
185 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
186 path = udev_list_entry_get_name(entry);
187 device = udev_device_new_from_syspath(udev, path);
188 parent = udev_device_get_parent(device);
189 usub = udev_device_get_subsystem(parent);
190 /* Filter out KMS output devices. */
191 if (!usub || (strcmp(usub, "pci") != 0))
192 continue;
193 pci_id = udev_device_get_property_value(parent, "PCI_ID");
194 if (fnmatch(pci_glob, pci_id, 0) != 0)
195 continue;
196 dnode = udev_device_get_devnode(device);
197 fd = open(dnode, O_RDWR);
198 if (fd < 0)
199 continue;
200 if (!is_render_node(fd, &st)) {
201 close(fd);
202 fd = -1;
203 continue;
204 }
205
206 pXglDev = &icd_data.gpu_info[count];
207
208 sscanf(pci_id, "%x:%x", &pXglDev->ven_id, &pXglDev->dev_id);
209 /*
210 * Currently only allowing Ivybridge and Haswell
211 */
212 if (!IS_HASWELL(pXglDev->dev_id) && !IS_IVYBRIDGE(pXglDev->dev_id)) {
213 close(fd);
214 fd = -1;
215 continue;
216 }
217
218 /*
219 * We'll keep the fd open for any subsequent
220 * xglGetGpuInfo calls.
221 */
222 pXglDev->fd = fd;
223 strncpy(pXglDev->device_path, dnode, XGL_MAX_PHYSICAL_GPU_NAME);
224 icd_data.render_node_list[count] = pXglDev;
225 init_xgl_dispatch_table(&pXglDev->xgl);
226 init_validation_dispatch_table(&pXglDev->validation);
227 pXglDev->exec = & pXglDev->xgl;
228
229 ret = XGL_SUCCESS;
230 count++;
231 }
232 icd_data.num_gpus = count;
233 udev_enumerate_unref(e);
234 udev_unref(udev);
235
236 if (ret == XGL_SUCCESS) {
237 *pGpuCount = icd_data.num_gpus;
238 memcpy(pGpus, icd_data.render_node_list,
239 (icd_data.num_gpus >
240 maxGpus ? maxGpus : icd_data.num_gpus) *
241 sizeof(XGL_PHYSICAL_GPU));
242 }
243
244 return ret;
245}
246
247XGL_RESULT XGLAPI GetExtensionSupport(XGL_PHYSICAL_GPU gpu, const XGL_CHAR* pExtName)
248{
249 // struct _xgl_device *pdev = (struct _xgl_device *) gpu;
250
251 // TODO: Check requested extension
252
253 return XGL_ERROR_INVALID_EXTENSION;
254}