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
370 class VulkanVideoDecodeParserLibrary : public vk::Library
371 {
372 public:
VulkanVideoDecodeParserLibrary(void)373 VulkanVideoDecodeParserLibrary(void)
374 : m_library("./libnvidia-vkvideo-parser.so")
375 {
376 }
377
getPlatformInterface(void) const378 const vk::PlatformInterface& getPlatformInterface(void) const
379 {
380 TCU_THROW(InternalError, "getPlatformInterface is not possible for VulkanVideoDecodeParserLibrary");
381 }
getFunctionLibrary(void) const382 const tcu::FunctionLibrary& getFunctionLibrary(void) const
383 {
384 return m_library;
385 }
386
387 private:
388 const tcu::DynamicFunctionLibrary m_library;
389 };
390
391
VulkanPlatform(EventState & eventState)392 VulkanPlatform::VulkanPlatform (EventState& eventState)
393 : m_eventState(eventState)
394 {
395 }
396
createWsiDisplay(vk::wsi::Type wsiType) const397 vk::wsi::Display* VulkanPlatform::createWsiDisplay (vk::wsi::Type wsiType) const
398 {
399 if (!hasDisplay(wsiType))
400 {
401 throw NotSupportedError("This display type is not available: ", NULL, __FILE__, __LINE__);
402 }
403
404 switch(wsiType)
405 {
406 #if defined (DEQP_SUPPORT_X11)
407 case vk::wsi::TYPE_XLIB:
408 return new VulkanDisplayXlib(MovePtr<x11::DisplayBase>(new x11::XlibDisplay(m_eventState,X11_DISPLAY)));
409 #endif // DEQP_SUPPORT_X11
410 #if defined (DEQP_SUPPORT_XCB)
411 case vk::wsi::TYPE_XCB:
412 return new VulkanDisplayXcb(MovePtr<x11::DisplayBase>(new x11::XcbDisplay(m_eventState,X11_DISPLAY)));
413 #endif // DEQP_SUPPORT_XCB
414 #if defined (DEQP_SUPPORT_WAYLAND)
415 case vk::wsi::TYPE_WAYLAND:
416 return new VulkanDisplayWayland(MovePtr<wayland::Display>(new wayland::Display(m_eventState, WAYLAND_DISPLAY)));
417 #endif // DEQP_SUPPORT_WAYLAND
418 #if defined (DEQP_SUPPORT_HEADLESS)
419 case vk::wsi::TYPE_HEADLESS:
420 return new VulkanDisplayHeadless();
421 #endif // DEQP_SUPPORT_HEADLESS
422 #if DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
423 case vk::wsi::TYPE_DIRECT_DRM:
424 return new VulkanDisplayDirectDrm();
425 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
426
427 default:
428 TCU_THROW(NotSupportedError, "WSI type not supported");
429
430 }
431 }
hasDisplay(vk::wsi::Type wsiType) const432 bool VulkanPlatform::hasDisplay (vk::wsi::Type wsiType) const
433 {
434 switch(wsiType)
435 {
436 #if defined (DEQP_SUPPORT_X11)
437 case vk::wsi::TYPE_XLIB:
438 return x11::XlibDisplay::hasDisplay(X11_DISPLAY);
439 #endif // DEQP_SUPPORT_X11
440 #if defined (DEQP_SUPPORT_XCB)
441 case vk::wsi::TYPE_XCB:
442 return x11::XcbDisplay::hasDisplay(X11_DISPLAY);
443 #endif // DEQP_SUPPORT_XCB
444 #if defined (DEQP_SUPPORT_WAYLAND)
445 case vk::wsi::TYPE_WAYLAND:
446 return wayland::Display::hasDisplay(WAYLAND_DISPLAY);
447 #endif // DEQP_SUPPORT_WAYLAND
448 #if defined (DEQP_SUPPORT_HEADLESS)
449 case vk::wsi::TYPE_HEADLESS:
450 return true;
451 #endif // DEQP_SUPPORT_HEADLESS
452 #if DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
453 case vk::wsi::TYPE_DIRECT_DRM:
454 return true;
455 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
456 default:
457 return false;
458
459 }
460 }
461
createLibrary(LibraryType libraryType,const char * libraryPath) const462 vk::Library* VulkanPlatform::createLibrary (LibraryType libraryType, const char* libraryPath) const
463 {
464 switch(libraryType)
465 {
466 case LIBRARY_TYPE_VULKAN: return new VulkanLibrary(libraryPath);
467 case LIBRARY_TYPE_VULKAN_VIDEO_DECODE_PARSER: return new VulkanVideoDecodeParserLibrary();
468
469 default: TCU_THROW(InternalError, "Unknown library type requested");
470 }
471 }
472
describePlatform(std::ostream & dst) const473 void VulkanPlatform::describePlatform (std::ostream& dst) const
474 {
475 utsname sysInfo;
476 deMemset(&sysInfo, 0, sizeof(sysInfo));
477
478 if (uname(&sysInfo) != 0)
479 throw std::runtime_error("uname() failed");
480
481 dst << "OS: " << sysInfo.sysname << " " << sysInfo.release << " " << sysInfo.version << "\n";
482 dst << "CPU: " << sysInfo.machine << "\n";
483 }
484
485 } // linux
486 } // tcu
487
488