1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Linux Vulkan Platform.
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuLnxVulkanPlatform.hpp"
25 #include "tcuLnxPlatform.hpp"
26 #include "vkDefs.hpp"
27 #include "vkDeviceUtil.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkWsiPlatform.hpp"
30 #include "gluPlatform.hpp"
31 #include "tcuLibDrm.hpp"
32 #include "tcuLnx.hpp"
33 #include "tcuFunctionLibrary.hpp"
34 #include "deUniquePtr.hpp"
35 #include "deMemory.h"
36
37 #include <sys/utsname.h>
38
39 using de::MovePtr;
40 using de::UniquePtr;
41 #if DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
42 using tcu::LibDrm;
43 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
44
45 #if defined (DEQP_SUPPORT_X11)
46 # include "tcuLnxX11.hpp"
47 # if defined (DEQP_SUPPORT_XCB)
48 # include "tcuLnxX11Xcb.hpp"
49 # endif // DEQP_SUPPORT_XCB
50 # define X11_DISPLAY ""
51 #endif // DEQP_SUPPORT_X11
52
53 #if defined (DEQP_SUPPORT_WAYLAND)
54 # include "tcuLnxWayland.hpp"
55 # define WAYLAND_DISPLAY DE_NULL
56 #endif // DEQP_SUPPORT_WAYLAND
57
58 #if !defined(DEQP_VULKAN_LIBRARY_PATH)
59 # define DEQP_VULKAN_LIBRARY_PATH "libvulkan.so.1"
60 #endif
61
62 namespace tcu
63 {
64 namespace lnx
65 {
66
67 #if defined (DEQP_SUPPORT_X11)
68
69 class VulkanWindowXlib : public vk::wsi::XlibWindowInterface
70 {
71 public:
VulkanWindowXlib(MovePtr<x11::XlibWindow> window)72 VulkanWindowXlib (MovePtr<x11::XlibWindow> window)
73 : vk::wsi::XlibWindowInterface (vk::pt::XlibWindow(window->getXID()))
74 , m_window (window)
75 {
76 }
77
setVisible(bool visible)78 void setVisible(bool visible)
79 {
80 m_window->setVisibility(visible);
81 }
82
resize(const UVec2 & newSize)83 void resize (const UVec2& newSize)
84 {
85 m_window->setDimensions((int)newSize.x(), (int)newSize.y());
86 }
87
setMinimized(bool minimized)88 void setMinimized(bool minimized)
89 {
90 DE_UNREF(minimized);
91 TCU_THROW(NotSupportedError, "Minimized on X11 is not implemented");
92 }
93
94 private:
95 UniquePtr<x11::XlibWindow> m_window;
96 };
97
98 class VulkanDisplayXlib : public vk::wsi::XlibDisplayInterface
99 {
100 public:
VulkanDisplayXlib(MovePtr<x11::DisplayBase> display)101 VulkanDisplayXlib (MovePtr<x11::DisplayBase> display)
102 : vk::wsi::XlibDisplayInterface (vk::pt::XlibDisplayPtr(((x11::XlibDisplay*)display.get())->getXDisplay()))
103 , m_display (display)
104 {
105 }
106
createWindow(const Maybe<UVec2> & initialSize) const107 vk::wsi::Window* createWindow (const Maybe<UVec2>& initialSize) const
108 {
109 x11::XlibDisplay* instance = (x11::XlibDisplay*)(m_display.get());
110 const deUint32 height = !initialSize ? (deUint32)DEFAULT_WINDOW_HEIGHT : initialSize->y();
111 const deUint32 width = !initialSize ? (deUint32)DEFAULT_WINDOW_WIDTH : initialSize->x();
112 return new VulkanWindowXlib(MovePtr<x11::XlibWindow>(new x11::XlibWindow(*instance, (int)width, (int)height, instance->getVisual(0))));
113 }
114
115 private:
116 MovePtr<x11::DisplayBase> m_display;
117 };
118
119 #endif // DEQP_SUPPORT_X11
120
121 #if defined (DEQP_SUPPORT_XCB)
122
123 class VulkanWindowXcb : public vk::wsi::XcbWindowInterface
124 {
125 public:
VulkanWindowXcb(MovePtr<x11::XcbWindow> window)126 VulkanWindowXcb (MovePtr<x11::XcbWindow> window)
127 : vk::wsi::XcbWindowInterface (vk::pt::XcbWindow(window->getXID()))
128 , m_window (window)
129 {
130 }
131
setVisible(bool visible)132 void setVisible(bool visible)
133 {
134 m_window->setVisibility(visible);
135 }
136
resize(const UVec2 & newSize)137 void resize (const UVec2& newSize)
138 {
139 m_window->setDimensions((int)newSize.x(), (int)newSize.y());
140 }
141
setMinimized(bool minimized)142 void setMinimized(bool minimized)
143 {
144 DE_UNREF(minimized);
145 TCU_THROW(NotSupportedError, "Minimized on xcb is not implemented");
146 }
147
148 private:
149 UniquePtr<x11::XcbWindow> m_window;
150 };
151
152 class VulkanDisplayXcb : public vk::wsi::XcbDisplayInterface
153 {
154 public:
VulkanDisplayXcb(MovePtr<x11::DisplayBase> display)155 VulkanDisplayXcb (MovePtr<x11::DisplayBase> display)
156 : vk::wsi::XcbDisplayInterface (vk::pt::XcbConnectionPtr(((x11::XcbDisplay*)display.get())->getConnection()))
157 , m_display (display)
158 {
159 }
160
createWindow(const Maybe<UVec2> & initialSize) const161 vk::wsi::Window* createWindow (const Maybe<UVec2>& initialSize) const
162 {
163 x11::XcbDisplay* instance = (x11::XcbDisplay*)(m_display.get());
164 const deUint32 height = !initialSize ? (deUint32)DEFAULT_WINDOW_HEIGHT : initialSize->y();
165 const deUint32 width = !initialSize ? (deUint32)DEFAULT_WINDOW_WIDTH : initialSize->x();
166 return new VulkanWindowXcb(MovePtr<x11::XcbWindow>(new x11::XcbWindow(*instance, (int)width, (int)height, DE_NULL)));
167 }
168
169 private:
170 MovePtr<x11::DisplayBase> m_display;
171 };
172 #endif // DEQP_SUPPORT_XCB
173
174 #if defined (DEQP_SUPPORT_WAYLAND)
175 class VulkanWindowWayland : public vk::wsi::WaylandWindowInterface
176 {
177 public:
VulkanWindowWayland(MovePtr<wayland::Window> window)178 VulkanWindowWayland (MovePtr<wayland::Window> window)
179 : vk::wsi::WaylandWindowInterface (vk::pt::WaylandSurfacePtr(window->getSurface()))
180 , m_window (window)
181 {
182 }
183
setVisible(bool visible)184 void setVisible(bool visible)
185 {
186 m_window->setVisibility(visible);
187 }
188
resize(const UVec2 & newSize)189 void resize (const UVec2& newSize)
190 {
191 m_window->setDimensions((int)newSize.x(), (int)newSize.y());
192 }
193
setMinimized(bool minimized)194 void setMinimized(bool minimized)
195 {
196 DE_UNREF(minimized);
197 TCU_THROW(NotSupportedError, "Minimized on wayland is not implemented");
198 }
199
200 private:
201 UniquePtr<wayland::Window> m_window;
202 };
203
204 class VulkanDisplayWayland : public vk::wsi::WaylandDisplayInterface
205 {
206 public:
VulkanDisplayWayland(MovePtr<wayland::Display> display)207 VulkanDisplayWayland (MovePtr<wayland::Display> display)
208 : vk::wsi::WaylandDisplayInterface (vk::pt::WaylandDisplayPtr(display->getDisplay()))
209 , m_display (display)
210 {
211 }
212
createWindow(const Maybe<UVec2> & initialSize) const213 vk::wsi::Window* createWindow (const Maybe<UVec2>& initialSize) const
214 {
215 const deUint32 height = !initialSize ? (deUint32)DEFAULT_WINDOW_HEIGHT : initialSize->y();
216 const deUint32 width = !initialSize ? (deUint32)DEFAULT_WINDOW_WIDTH : initialSize->x();
217 return new VulkanWindowWayland(MovePtr<wayland::Window>(new wayland::Window(*m_display, (int)width, (int)height)));
218 }
219
220 private:
221 MovePtr<wayland::Display> m_display;
222 };
223 #endif // DEQP_SUPPORT_WAYLAND
224
225 #if defined (DEQP_SUPPORT_HEADLESS)
226
227 struct VulkanWindowHeadless : public vk::wsi::Window
228 {
229 public:
resizetcu::lnx::VulkanWindowHeadless230 void resize (const UVec2&)
231 {
232 }
233 };
234
235 class VulkanDisplayHeadless : public vk::wsi::Display
236 {
237 public:
VulkanDisplayHeadless()238 VulkanDisplayHeadless ()
239 {
240 }
241
createWindow(const Maybe<UVec2> &) const242 vk::wsi::Window* createWindow (const Maybe<UVec2>&) const
243 {
244 return new VulkanWindowHeadless();
245 }
246 };
247
248 #endif // DEQP_SUPPORT_HEADLESS
249
250 #if DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
251
252 struct VulkanWindowDirectDrm : public vk::wsi::Window
253 {
254 public:
resizetcu::lnx::VulkanWindowDirectDrm255 void resize (const UVec2&)
256 {
257 }
258 };
259
260 class VulkanDisplayDirectDrm : public vk::wsi::DirectDrmDisplayInterface
261 {
262 public:
VulkanDisplayDirectDrm(void)263 VulkanDisplayDirectDrm (void)
264 {
265 }
266
createWindow(const Maybe<UVec2> &) const267 vk::wsi::Window* createWindow (const Maybe<UVec2>&) const override
268 {
269 return new VulkanWindowDirectDrm();
270 }
271
initializeDisplay(const vk::InstanceInterface & vki,vk::VkInstance instance,const tcu::CommandLine & cmdLine)272 void initializeDisplay (const vk::InstanceInterface& vki, vk::VkInstance instance, const tcu::CommandLine& cmdLine) override
273 {
274 if (m_initialized)
275 return;
276
277 vk::VkPhysicalDevice physDevice = vk::chooseDevice(vki, instance, cmdLine);
278
279 /* Get a Drm fd that matches the device. */
280
281 vk::VkPhysicalDeviceProperties2 deviceProperties2;
282 vk::VkPhysicalDeviceDrmPropertiesEXT deviceDrmProperties;
283
284 deMemset(&deviceDrmProperties, 0, sizeof(deviceDrmProperties));
285 deviceDrmProperties.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT;
286 deviceDrmProperties.pNext = DE_NULL;
287
288 deMemset(&deviceProperties2, 0, sizeof(deviceProperties2));
289 deviceProperties2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
290 deviceProperties2.pNext = &deviceDrmProperties;
291
292 vki.getPhysicalDeviceProperties2(physDevice, &deviceProperties2);
293
294 if (!deviceDrmProperties.hasPrimary)
295 TCU_THROW(NotSupportedError, "No DRM primary device.");
296
297 LibDrm libDrm;
298 int numDrmDevices;
299 drmDevicePtr* drmDevices = libDrm.getDevices(&numDrmDevices);
300 const char* drmNode = libDrm.findDeviceNode(drmDevices, numDrmDevices, deviceDrmProperties.primaryMajor, deviceDrmProperties.primaryMinor);
301
302 if (!drmNode)
303 TCU_THROW(NotSupportedError, "No DRM node.");
304
305 m_fdPtr = libDrm.openFd(drmNode).move();
306 if (!m_fdPtr)
307 TCU_THROW(NotSupportedError, "Could not open DRM.");
308 int fd = *m_fdPtr;
309
310 /* Get a connector to the display. */
311
312 LibDrm::ResPtr res = libDrm.getResources(fd);
313 if (!res)
314 TCU_THROW(NotSupportedError, "Could not get DRM resources.");
315
316 deUint32 connectorId = 0;
317 for (int i = 0; i < res->count_connectors; ++i) {
318 LibDrm::ConnectorPtr conn = libDrm.getConnector(fd, res->connectors[i]);
319
320 if (conn && conn->connection == DRM_MODE_CONNECTED) {
321 connectorId = res->connectors[i];
322 break;
323 }
324 }
325 if (!connectorId)
326 TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
327
328 /* Get and acquire the display for the connector. */
329
330 vk::VkDisplayKHR* display = const_cast<vk::VkDisplayKHR*>(&m_native);
331 VK_CHECK_SUPPORTED(vki.getDrmDisplayEXT(physDevice, fd, connectorId, display));
332
333 if (m_native == DE_NULL)
334 TCU_THROW(NotSupportedError, "vkGetDrmDisplayEXT did not set display.");
335
336 VK_CHECK_SUPPORTED(vki.acquireDrmDisplayEXT(physDevice, fd, m_native));
337 m_initialized = true;
338 }
339
340 MovePtr<LibDrm::FdPtr::element_type, LibDrm::FdPtr::deleter_type> m_fdPtr;
341 bool m_initialized = false;
342 };
343
344 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
345
346 class VulkanLibrary : public vk::Library
347 {
348 public:
VulkanLibrary(const char * libraryPath)349 VulkanLibrary (const char* libraryPath)
350 : m_library (libraryPath != DE_NULL ? libraryPath : DEQP_VULKAN_LIBRARY_PATH)
351 , m_driver (m_library)
352 {
353 }
354
getPlatformInterface(void) const355 const vk::PlatformInterface& getPlatformInterface (void) const
356 {
357 return m_driver;
358 }
359
getFunctionLibrary(void) const360 const tcu::FunctionLibrary& getFunctionLibrary (void) const
361 {
362 return m_library;
363 }
364
365 private:
366 const DynamicFunctionLibrary m_library;
367 const vk::PlatformDriver m_driver;
368 };
369
VulkanPlatform(EventState & eventState)370 VulkanPlatform::VulkanPlatform (EventState& eventState)
371 : m_eventState(eventState)
372 {
373 }
374
createWsiDisplay(vk::wsi::Type wsiType) const375 vk::wsi::Display* VulkanPlatform::createWsiDisplay (vk::wsi::Type wsiType) const
376 {
377 if (!hasDisplay(wsiType))
378 {
379 throw NotSupportedError("This display type is not available: ", NULL, __FILE__, __LINE__);
380 }
381
382 switch(wsiType)
383 {
384 #if defined (DEQP_SUPPORT_X11)
385 case vk::wsi::TYPE_XLIB:
386 return new VulkanDisplayXlib(MovePtr<x11::DisplayBase>(new x11::XlibDisplay(m_eventState,X11_DISPLAY)));
387 #endif // DEQP_SUPPORT_X11
388 #if defined (DEQP_SUPPORT_XCB)
389 case vk::wsi::TYPE_XCB:
390 return new VulkanDisplayXcb(MovePtr<x11::DisplayBase>(new x11::XcbDisplay(m_eventState,X11_DISPLAY)));
391 #endif // DEQP_SUPPORT_XCB
392 #if defined (DEQP_SUPPORT_WAYLAND)
393 case vk::wsi::TYPE_WAYLAND:
394 return new VulkanDisplayWayland(MovePtr<wayland::Display>(new wayland::Display(m_eventState, WAYLAND_DISPLAY)));
395 #endif // DEQP_SUPPORT_WAYLAND
396 #if defined (DEQP_SUPPORT_HEADLESS)
397 case vk::wsi::TYPE_HEADLESS:
398 return new VulkanDisplayHeadless();
399 #endif // DEQP_SUPPORT_HEADLESS
400 #if DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
401 case vk::wsi::TYPE_DIRECT_DRM:
402 return new VulkanDisplayDirectDrm();
403 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
404
405 default:
406 TCU_THROW(NotSupportedError, "WSI type not supported");
407
408 }
409 }
hasDisplay(vk::wsi::Type wsiType) const410 bool VulkanPlatform::hasDisplay (vk::wsi::Type wsiType) const
411 {
412 switch(wsiType)
413 {
414 #if defined (DEQP_SUPPORT_X11)
415 case vk::wsi::TYPE_XLIB:
416 return x11::XlibDisplay::hasDisplay(X11_DISPLAY);
417 #endif // DEQP_SUPPORT_X11
418 #if defined (DEQP_SUPPORT_XCB)
419 case vk::wsi::TYPE_XCB:
420 return x11::XcbDisplay::hasDisplay(X11_DISPLAY);
421 #endif // DEQP_SUPPORT_XCB
422 #if defined (DEQP_SUPPORT_WAYLAND)
423 case vk::wsi::TYPE_WAYLAND:
424 return wayland::Display::hasDisplay(WAYLAND_DISPLAY);
425 #endif // DEQP_SUPPORT_WAYLAND
426 #if defined (DEQP_SUPPORT_HEADLESS)
427 case vk::wsi::TYPE_HEADLESS:
428 return true;
429 #endif // DEQP_SUPPORT_HEADLESS
430 #if DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
431 case vk::wsi::TYPE_DIRECT_DRM:
432 return true;
433 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
434 default:
435 return false;
436
437 }
438 }
439
createLibrary(LibraryType libraryType,const char * libraryPath) const440 vk::Library* VulkanPlatform::createLibrary (LibraryType libraryType, const char* libraryPath) const
441 {
442 switch(libraryType)
443 {
444 case LIBRARY_TYPE_VULKAN: return new VulkanLibrary(libraryPath);
445
446 default: TCU_THROW(InternalError, "Unknown library type requested");
447 }
448 }
449
describePlatform(std::ostream & dst) const450 void VulkanPlatform::describePlatform (std::ostream& dst) const
451 {
452 utsname sysInfo;
453 deMemset(&sysInfo, 0, sizeof(sysInfo));
454
455 if (uname(&sysInfo) != 0)
456 throw std::runtime_error("uname() failed");
457
458 dst << "OS: " << sysInfo.sysname << " " << sysInfo.release << " " << sysInfo.version << "\n";
459 dst << "CPU: " << sysInfo.machine << "\n";
460 }
461
462 } // linux
463 } // tcu
464
465