egl: add EGL_MESA_device_software support
[mesa.git] / src / egl / main / egldevice.c
1 /**************************************************************************
2 *
3 * Copyright 2015, 2018 Collabora
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 OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "util/macros.h"
29
30 #include "eglcurrent.h"
31 #include "egldevice.h"
32 #include "eglglobals.h"
33 #include "egltypedefs.h"
34
35
36 struct _egl_device {
37 _EGLDevice *Next;
38
39 const char *extensions;
40
41 EGLBoolean MESA_device_software;
42 };
43
44 void
45 _eglFiniDevice(void)
46 {
47 _EGLDevice *dev_list, *dev;
48
49 /* atexit function is called with global mutex locked */
50
51 dev_list = _eglGlobal.DeviceList;
52
53 /* The first device is static allocated SW device */
54 assert(dev_list);
55 assert(_eglDeviceSupports(dev_list, _EGL_DEVICE_SOFTWARE));
56 dev_list = dev_list->Next;
57
58 while (dev_list) {
59 /* pop list head */
60 dev = dev_list;
61 dev_list = dev_list->Next;
62
63 free(dev);
64 }
65
66 _eglGlobal.DeviceList = NULL;
67 }
68
69 EGLBoolean
70 _eglCheckDeviceHandle(EGLDeviceEXT device)
71 {
72 _EGLDevice *cur;
73
74 mtx_lock(_eglGlobal.Mutex);
75 cur = _eglGlobal.DeviceList;
76 while (cur) {
77 if (cur == (_EGLDevice *) device)
78 break;
79 cur = cur->Next;
80 }
81 mtx_unlock(_eglGlobal.Mutex);
82 return (cur != NULL);
83 }
84
85 _EGLDevice _eglSoftwareDevice = {
86 .extensions = "EGL_MESA_device_software",
87 .MESA_device_software = EGL_TRUE,
88 };
89
90 /* Adds a device in DeviceList, if needed for the given fd.
91 *
92 * If a software device, the fd is ignored.
93 */
94 _EGLDevice *
95 _eglAddDevice(int fd, bool software)
96 {
97 _EGLDevice *dev;
98
99 mtx_lock(_eglGlobal.Mutex);
100 dev = _eglGlobal.DeviceList;
101
102 /* The first device is always software */
103 assert(dev);
104 assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
105 if (software)
106 goto out;
107
108 dev = NULL;
109
110 out:
111 mtx_unlock(_eglGlobal.Mutex);
112 return dev;
113 }
114
115 EGLBoolean
116 _eglDeviceSupports(_EGLDevice *dev, _EGLDeviceExtension ext)
117 {
118 switch (ext) {
119 case _EGL_DEVICE_SOFTWARE:
120 return dev->MESA_device_software;
121 default:
122 assert(0);
123 return EGL_FALSE;
124 };
125 }
126
127 EGLBoolean
128 _eglQueryDeviceAttribEXT(_EGLDevice *dev, EGLint attribute,
129 EGLAttrib *value)
130 {
131 switch (attribute) {
132 default:
133 _eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceStringEXT");
134 return EGL_FALSE;
135 }
136 }
137
138 const char *
139 _eglQueryDeviceStringEXT(_EGLDevice *dev, EGLint name)
140 {
141 switch (name) {
142 case EGL_EXTENSIONS:
143 return dev->extensions;
144 default:
145 _eglError(EGL_BAD_PARAMETER, "eglQueryDeviceStringEXT");
146 return NULL;
147 };
148 }
149
150 /* Do a fresh lookup for devices.
151 *
152 * Walks through the DeviceList, discarding no longer available ones
153 * and adding new ones as applicable.
154 *
155 * Must be called with the global lock held.
156 */
157 static int
158 _eglRefreshDeviceList(void)
159 {
160 MAYBE_UNUSED _EGLDevice *dev;
161 int count = 0;
162
163 dev = _eglGlobal.DeviceList;
164
165 /* The first device is always software */
166 assert(dev);
167 assert(_eglDeviceSupports(dev, _EGL_DEVICE_SOFTWARE));
168 count++;
169
170 return count;
171 }
172
173 EGLBoolean
174 _eglQueryDevicesEXT(EGLint max_devices,
175 _EGLDevice **devices,
176 EGLint *num_devices)
177 {
178 _EGLDevice *dev, *devs;
179 int i = 0, num_devs;
180
181 if ((devices && max_devices <= 0) || !num_devices)
182 return _eglError(EGL_BAD_PARAMETER, "eglQueryDevicesEXT");
183
184 mtx_lock(_eglGlobal.Mutex);
185
186 num_devs = _eglRefreshDeviceList();
187 devs = _eglGlobal.DeviceList;
188
189 /* bail early if we only care about the count */
190 if (!devices) {
191 *num_devices = num_devs;
192 goto out;
193 }
194
195 *num_devices = MIN2(num_devs, max_devices);
196
197 for (i = 0, dev = devs; i < *num_devices; i++) {
198 devices[i] = dev;
199 dev = dev->Next;
200 }
201
202 out:
203 mtx_unlock(_eglGlobal.Mutex);
204
205 return EGL_TRUE;
206 }