blob: 589ae25fad2a7ac765377293a2685112c8a47ac6 [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
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -060091static int is_render_node(int fd, struct stat *st)
92{
93 if (fstat(fd, st))
94 return 0;
95
96 if (!S_ISCHR(st->st_mode))
97 return 0;
98
99 return st->st_rdev & 0x80;
100}
101
102static void init_xgl_dispatch_table(struct icd_dispatch_table *pDispatch)
103{
104#define LOAD(xglfunc, driverfunc) do { \
105 pDispatch->xglfunc = driverfunc; \
106} while (0)
107 LOAD(GetGpuInfo, gen7_GetGpuInfo);
108 LOAD(GetExtensionSupport, GetExtensionSupport);
109}
110
111static void init_validation_dispatch_table(struct icd_dispatch_table *pDispatch)
112{
113#define LOAD(xglfunc, driverfunc) do { \
114 pDispatch->xglfunc = driverfunc; \
115} while (0)
116 LOAD(GetGpuInfo, gen7_GetGpuInfo);
117 LOAD(GetExtensionSupport, GetExtensionSupport);
118}
119
120ICDENTRY XGL_RESULT XGLAPI xglInitAndEnumerateGpus(const XGL_APPLICATION_INFO *
121 pAppInfo,
122 const XGL_ALLOC_CALLBACKS *
123 pAllocCb, XGL_UINT maxGpus,
124 XGL_UINT * pGpuCount,
125 XGL_PHYSICAL_GPU * pGpus)
126{
127 struct udev *udev;
128 struct udev_enumerate *e;
129 struct udev_device *device, *parent;
130 struct udev_list_entry *entry;
131 const char *pci_id, *path;
132 const char *usub, *dnode;
133 int fd;
134 struct stat st;
135 char *pci_glob = "*:*";
Chia-I Wu3065c9c2014-08-04 06:28:31 +0800136 XGL_RESULT ret;
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600137 XGL_UINT count = 0;
138 struct _xgl_device *pXglDev;
139
Chia-I Wu3065c9c2014-08-04 06:28:31 +0800140 ret = icd_set_alloc_callbacks(pAllocCb);
141 if (ret != XGL_SUCCESS)
142 return ret;
143
144 ret = XGL_ERROR_UNAVAILABLE;
145
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600146 // TODO: Do we need to keep track of previous calls to xglInitAndEnumerageGpus?
147 /*
148 * xglInitAndEnumerateGpus() can be called multiple times. Calling it more than once
149 * forces driver reinitialization.
150 */
151
152 if (icd_data.num_gpus > 0) {
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600153 // TODO: Free resources and re-initialize
154 }
155 // TODO: Do we need any other validation for incoming pointers?
156
Courtney Goeltzenleuchtere06e72d2014-08-01 12:44:23 -0600157 udev = udev_new();
158 if (udev == NULL) {
159 loader_err(0, "failed to initialize udev context");
160 abort();
161 }
162
163 memset(icd_data.gpu_info, 0,
164 sizeof(icd_data.gpu_info[XGL_MAX_PHYSICAL_GPUS]));
165 memset(icd_data.render_node_list, 0,
166 sizeof(icd_data.render_node_list[XGL_MAX_PHYSICAL_GPUS]));
167
168 fd = -1;
169 e = udev_enumerate_new(udev);
170 udev_enumerate_add_match_subsystem(e, "drm");
171 udev_enumerate_scan_devices(e);
172 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
173 path = udev_list_entry_get_name(entry);
174 device = udev_device_new_from_syspath(udev, path);
175 parent = udev_device_get_parent(device);
176 usub = udev_device_get_subsystem(parent);
177 /* Filter out KMS output devices. */
178 if (!usub || (strcmp(usub, "pci") != 0))
179 continue;
180 pci_id = udev_device_get_property_value(parent, "PCI_ID");
181 if (fnmatch(pci_glob, pci_id, 0) != 0)
182 continue;
183 dnode = udev_device_get_devnode(device);
184 fd = open(dnode, O_RDWR);
185 if (fd < 0)
186 continue;
187 if (!is_render_node(fd, &st)) {
188 close(fd);
189 fd = -1;
190 continue;
191 }
192
193 pXglDev = &icd_data.gpu_info[count];
194
195 sscanf(pci_id, "%x:%x", &pXglDev->ven_id, &pXglDev->dev_id);
196 /*
197 * Currently only allowing Ivybridge and Haswell
198 */
199 if (!IS_HASWELL(pXglDev->dev_id) && !IS_IVYBRIDGE(pXglDev->dev_id)) {
200 close(fd);
201 fd = -1;
202 continue;
203 }
204
205 /*
206 * We'll keep the fd open for any subsequent
207 * xglGetGpuInfo calls.
208 */
209 pXglDev->fd = fd;
210 strncpy(pXglDev->device_path, dnode, XGL_MAX_PHYSICAL_GPU_NAME);
211 icd_data.render_node_list[count] = pXglDev;
212 init_xgl_dispatch_table(&pXglDev->xgl);
213 init_validation_dispatch_table(&pXglDev->validation);
214 pXglDev->exec = & pXglDev->xgl;
215
216 ret = XGL_SUCCESS;
217 count++;
218 }
219 icd_data.num_gpus = count;
220 udev_enumerate_unref(e);
221 udev_unref(udev);
222
223 if (ret == XGL_SUCCESS) {
224 *pGpuCount = icd_data.num_gpus;
225 memcpy(pGpus, icd_data.render_node_list,
226 (icd_data.num_gpus >
227 maxGpus ? maxGpus : icd_data.num_gpus) *
228 sizeof(XGL_PHYSICAL_GPU));
229 }
230
231 return ret;
232}
233
234XGL_RESULT XGLAPI GetExtensionSupport(XGL_PHYSICAL_GPU gpu, const XGL_CHAR* pExtName)
235{
236 // struct _xgl_device *pdev = (struct _xgl_device *) gpu;
237
238 // TODO: Check requested extension
239
240 return XGL_ERROR_INVALID_EXTENSION;
241}