• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 nullptr
56 #endif // DEQP_SUPPORT_WAYLAND
57 
58 #if !defined(DEQP_VULKAN_LIBRARY_PATH)
59 #ifdef CTS_USES_VULKANSC
60 #define DEQP_VULKAN_LIBRARY_PATH "libvulkansc.so.1"
61 #else
62 #define DEQP_VULKAN_LIBRARY_PATH "libvulkan.so.1"
63 #endif
64 #endif
65 
66 namespace tcu
67 {
68 namespace lnx
69 {
70 
71 #if defined(DEQP_SUPPORT_X11)
72 
73 class VulkanWindowXlib : public vk::wsi::XlibWindowInterface
74 {
75 public:
VulkanWindowXlib(MovePtr<x11::XlibWindow> window)76     VulkanWindowXlib(MovePtr<x11::XlibWindow> window)
77         : vk::wsi::XlibWindowInterface(vk::pt::XlibWindow(window->getXID()))
78         , m_window(window)
79     {
80     }
81 
setVisible(bool visible)82     void setVisible(bool visible)
83     {
84         m_window->setVisibility(visible);
85     }
86 
resize(const UVec2 & newSize)87     void resize(const UVec2 &newSize)
88     {
89         m_window->setDimensions((int)newSize.x(), (int)newSize.y());
90     }
91 
setMinimized(bool minimized)92     void setMinimized(bool minimized)
93     {
94         DE_UNREF(minimized);
95         TCU_THROW(NotSupportedError, "Minimized on X11 is not implemented");
96     }
97 
98 private:
99     UniquePtr<x11::XlibWindow> m_window;
100 };
101 
102 class VulkanDisplayXlib : public vk::wsi::XlibDisplayInterface
103 {
104 public:
VulkanDisplayXlib(MovePtr<x11::DisplayBase> display)105     VulkanDisplayXlib(MovePtr<x11::DisplayBase> display)
106         : vk::wsi::XlibDisplayInterface(vk::pt::XlibDisplayPtr(((x11::XlibDisplay *)display.get())->getXDisplay()))
107         , m_display(display)
108     {
109     }
110 
createWindow(const Maybe<UVec2> & initialSize) const111     vk::wsi::Window *createWindow(const Maybe<UVec2> &initialSize) const
112     {
113         x11::XlibDisplay *instance = (x11::XlibDisplay *)(m_display.get());
114         const uint32_t height      = !initialSize ? (uint32_t)DEFAULT_WINDOW_HEIGHT : initialSize->y();
115         const uint32_t width       = !initialSize ? (uint32_t)DEFAULT_WINDOW_WIDTH : initialSize->x();
116         return new VulkanWindowXlib(
117             MovePtr<x11::XlibWindow>(new x11::XlibWindow(*instance, (int)width, (int)height, instance->getVisual(0))));
118     }
119 
120 private:
121     MovePtr<x11::DisplayBase> m_display;
122 };
123 
124 #endif // DEQP_SUPPORT_X11
125 
126 #if defined(DEQP_SUPPORT_XCB)
127 
128 class VulkanWindowXcb : public vk::wsi::XcbWindowInterface
129 {
130 public:
VulkanWindowXcb(MovePtr<x11::XcbWindow> window)131     VulkanWindowXcb(MovePtr<x11::XcbWindow> window)
132         : vk::wsi::XcbWindowInterface(vk::pt::XcbWindow(window->getXID()))
133         , m_window(window)
134     {
135     }
136 
setVisible(bool visible)137     void setVisible(bool visible)
138     {
139         m_window->setVisibility(visible);
140     }
141 
resize(const UVec2 & newSize)142     void resize(const UVec2 &newSize)
143     {
144         m_window->setDimensions((int)newSize.x(), (int)newSize.y());
145     }
146 
setMinimized(bool minimized)147     void setMinimized(bool minimized)
148     {
149         DE_UNREF(minimized);
150         TCU_THROW(NotSupportedError, "Minimized on xcb is not implemented");
151     }
152 
153 private:
154     UniquePtr<x11::XcbWindow> m_window;
155 };
156 
157 class VulkanDisplayXcb : public vk::wsi::XcbDisplayInterface
158 {
159 public:
VulkanDisplayXcb(MovePtr<x11::DisplayBase> display)160     VulkanDisplayXcb(MovePtr<x11::DisplayBase> display)
161         : vk::wsi::XcbDisplayInterface(vk::pt::XcbConnectionPtr(((x11::XcbDisplay *)display.get())->getConnection()))
162         , m_display(display)
163     {
164     }
165 
createWindow(const Maybe<UVec2> & initialSize) const166     vk::wsi::Window *createWindow(const Maybe<UVec2> &initialSize) const
167     {
168         x11::XcbDisplay *instance = (x11::XcbDisplay *)(m_display.get());
169         const uint32_t height     = !initialSize ? (uint32_t)DEFAULT_WINDOW_HEIGHT : initialSize->y();
170         const uint32_t width      = !initialSize ? (uint32_t)DEFAULT_WINDOW_WIDTH : initialSize->x();
171         return new VulkanWindowXcb(
172             MovePtr<x11::XcbWindow>(new x11::XcbWindow(*instance, (int)width, (int)height, nullptr)));
173     }
174 
175 private:
176     MovePtr<x11::DisplayBase> m_display;
177 };
178 #endif // DEQP_SUPPORT_XCB
179 
180 #if defined(DEQP_SUPPORT_WAYLAND)
181 class VulkanWindowWayland : public vk::wsi::WaylandWindowInterface
182 {
183 public:
VulkanWindowWayland(MovePtr<wayland::Window> window)184     VulkanWindowWayland(MovePtr<wayland::Window> window)
185         : vk::wsi::WaylandWindowInterface(vk::pt::WaylandSurfacePtr(window->getSurface()))
186         , m_window(window)
187     {
188     }
189 
setVisible(bool visible)190     void setVisible(bool visible)
191     {
192         m_window->setVisibility(visible);
193     }
194 
resize(const UVec2 & newSize)195     void resize(const UVec2 &newSize)
196     {
197         m_window->setDimensions((int)newSize.x(), (int)newSize.y());
198     }
199 
setMinimized(bool minimized)200     void setMinimized(bool minimized)
201     {
202         DE_UNREF(minimized);
203         TCU_THROW(NotSupportedError, "Minimized on wayland is not implemented");
204     }
205 
206 private:
207     UniquePtr<wayland::Window> m_window;
208 };
209 
210 class VulkanDisplayWayland : public vk::wsi::WaylandDisplayInterface
211 {
212 public:
VulkanDisplayWayland(MovePtr<wayland::Display> display)213     VulkanDisplayWayland(MovePtr<wayland::Display> display)
214         : vk::wsi::WaylandDisplayInterface(vk::pt::WaylandDisplayPtr(display->getDisplay()))
215         , m_display(display)
216     {
217     }
218 
createWindow(const Maybe<UVec2> & initialSize) const219     vk::wsi::Window *createWindow(const Maybe<UVec2> &initialSize) const
220     {
221         const uint32_t height = !initialSize ? (uint32_t)DEFAULT_WINDOW_HEIGHT : initialSize->y();
222         const uint32_t width  = !initialSize ? (uint32_t)DEFAULT_WINDOW_WIDTH : initialSize->x();
223         return new VulkanWindowWayland(
224             MovePtr<wayland::Window>(new wayland::Window(*m_display, (int)width, (int)height)));
225     }
226 
227 private:
228     MovePtr<wayland::Display> m_display;
229 };
230 #endif // DEQP_SUPPORT_WAYLAND
231 
232 #if defined(DEQP_SUPPORT_HEADLESS)
233 
234 struct VulkanWindowHeadless : public vk::wsi::Window
235 {
236 public:
resizetcu::lnx::VulkanWindowHeadless237     void resize(const UVec2 &)
238     {
239     }
240 };
241 
242 class VulkanDisplayHeadless : public vk::wsi::Display
243 {
244 public:
VulkanDisplayHeadless()245     VulkanDisplayHeadless()
246     {
247     }
248 
createWindow(const Maybe<UVec2> &) const249     vk::wsi::Window *createWindow(const Maybe<UVec2> &) const
250     {
251         return new VulkanWindowHeadless();
252     }
253 };
254 
255 #endif // DEQP_SUPPORT_HEADLESS
256 
257 #if DEQP_SUPPORT_DRM && !defined(CTS_USES_VULKANSC)
258 
259 struct VulkanWindowDirectDrm : public vk::wsi::Window
260 {
261 public:
setVisibletcu::lnx::VulkanWindowDirectDrm262     void setVisible(bool visible) override
263     {
264         DE_UNREF(visible);
265     }
resizetcu::lnx::VulkanWindowDirectDrm266     void resize(const UVec2 &) override
267     {
268     }
269 };
270 
271 class VulkanDisplayDirectDrm : public vk::wsi::DirectDrmDisplayInterface
272 {
273 public:
VulkanDisplayDirectDrm(void)274     VulkanDisplayDirectDrm(void)
275     {
276     }
277 
createWindow(const Maybe<UVec2> &) const278     vk::wsi::Window *createWindow(const Maybe<UVec2> &) const override
279     {
280         return new VulkanWindowDirectDrm();
281     }
282 
initializeDisplay(const vk::InstanceInterface & vki,vk::VkInstance instance,const tcu::CommandLine & cmdLine)283     void initializeDisplay(const vk::InstanceInterface &vki, vk::VkInstance instance,
284                            const tcu::CommandLine &cmdLine) override
285     {
286         if (m_initialized)
287             return;
288 
289         vk::VkPhysicalDevice physDevice = vk::chooseDevice(vki, instance, cmdLine);
290 
291         /* Get a Drm fd that matches the device. */
292 
293         vk::VkPhysicalDeviceProperties2 deviceProperties2;
294         vk::VkPhysicalDeviceDrmPropertiesEXT deviceDrmProperties;
295 
296         deMemset(&deviceDrmProperties, 0, sizeof(deviceDrmProperties));
297         deviceDrmProperties.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT;
298         deviceDrmProperties.pNext = nullptr;
299 
300         deMemset(&deviceProperties2, 0, sizeof(deviceProperties2));
301         deviceProperties2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
302         deviceProperties2.pNext = &deviceDrmProperties;
303 
304         vki.getPhysicalDeviceProperties2(physDevice, &deviceProperties2);
305 
306         if (!deviceDrmProperties.hasPrimary)
307             TCU_THROW(NotSupportedError, "No DRM primary device.");
308 
309         LibDrm libDrm;
310         int numDrmDevices;
311         drmDevicePtr *drmDevices = libDrm.getDevices(&numDrmDevices);
312         const char *drmNode      = libDrm.findDeviceNode(drmDevices, numDrmDevices, deviceDrmProperties.primaryMajor,
313                                                          deviceDrmProperties.primaryMinor);
314 
315         if (!drmNode)
316             TCU_THROW(NotSupportedError, "No DRM node.");
317 
318         m_fdPtr = libDrm.openFd(drmNode).move();
319         if (!m_fdPtr)
320             TCU_THROW(NotSupportedError, "Could not open DRM.");
321         int fd = *m_fdPtr;
322 
323         /* Get a connector to the display. */
324 
325         LibDrm::ResPtr res = libDrm.getResources(fd);
326         if (!res)
327             TCU_THROW(NotSupportedError, "Could not get DRM resources.");
328 
329         uint32_t connectorId = 0;
330         for (int i = 0; i < res->count_connectors; ++i)
331         {
332             LibDrm::ConnectorPtr conn = libDrm.getConnector(fd, res->connectors[i]);
333 
334             if (conn && conn->connection == DRM_MODE_CONNECTED)
335             {
336                 connectorId = res->connectors[i];
337                 break;
338             }
339         }
340         if (!connectorId)
341             TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
342 
343         /* Get and acquire the display for the connector. */
344 
345         vk::VkDisplayKHR *display = const_cast<vk::VkDisplayKHR *>(&m_native);
346         VK_CHECK_SUPPORTED(vki.getDrmDisplayEXT(physDevice, fd, connectorId, display));
347 
348         if (m_native == VK_NULL_HANDLE)
349             TCU_THROW(NotSupportedError, "vkGetDrmDisplayEXT did not set display.");
350 
351         VK_CHECK_SUPPORTED(vki.acquireDrmDisplayEXT(physDevice, fd, m_native));
352         m_initialized = true;
353     }
354 
355     MovePtr<LibDrm::FdPtr::element_type, LibDrm::FdPtr::deleter_type> m_fdPtr;
356     bool m_initialized = false;
357 };
358 
359 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
360 
361 class VulkanLibrary : public vk::Library
362 {
363 public:
VulkanLibrary(const char * libraryPath)364     VulkanLibrary(const char *libraryPath)
365         : m_library(libraryPath != nullptr ? libraryPath : DEQP_VULKAN_LIBRARY_PATH)
366         , m_driver(m_library)
367     {
368     }
369 
getPlatformInterface(void) const370     const vk::PlatformInterface &getPlatformInterface(void) const
371     {
372         return m_driver;
373     }
374 
getFunctionLibrary(void) const375     const tcu::FunctionLibrary &getFunctionLibrary(void) const
376     {
377         return m_library;
378     }
379 
380 private:
381     const DynamicFunctionLibrary m_library;
382     const vk::PlatformDriver m_driver;
383 };
384 
VulkanPlatform(EventState & eventState)385 VulkanPlatform::VulkanPlatform(EventState &eventState) : m_eventState(eventState)
386 {
387 }
388 
createWsiDisplay(vk::wsi::Type wsiType) const389 vk::wsi::Display *VulkanPlatform::createWsiDisplay(vk::wsi::Type wsiType) const
390 {
391     if (!hasDisplay(wsiType))
392     {
393         throw NotSupportedError("This display type is not available: ", NULL, __FILE__, __LINE__);
394     }
395 
396     switch (wsiType)
397     {
398 #if defined(DEQP_SUPPORT_X11)
399     case vk::wsi::TYPE_XLIB:
400         return new VulkanDisplayXlib(MovePtr<x11::DisplayBase>(new x11::XlibDisplay(m_eventState, X11_DISPLAY)));
401 #endif // DEQP_SUPPORT_X11
402 #if defined(DEQP_SUPPORT_XCB)
403     case vk::wsi::TYPE_XCB:
404         return new VulkanDisplayXcb(MovePtr<x11::DisplayBase>(new x11::XcbDisplay(m_eventState, X11_DISPLAY)));
405 #endif // DEQP_SUPPORT_XCB
406 #if defined(DEQP_SUPPORT_WAYLAND)
407     case vk::wsi::TYPE_WAYLAND:
408         return new VulkanDisplayWayland(MovePtr<wayland::Display>(new wayland::Display(m_eventState, WAYLAND_DISPLAY)));
409 #endif // DEQP_SUPPORT_WAYLAND
410 #if defined(DEQP_SUPPORT_HEADLESS)
411     case vk::wsi::TYPE_HEADLESS:
412         return new VulkanDisplayHeadless();
413 #endif // DEQP_SUPPORT_HEADLESS
414 #if DEQP_SUPPORT_DRM && !defined(CTS_USES_VULKANSC)
415     case vk::wsi::TYPE_DIRECT_DRM:
416         return new VulkanDisplayDirectDrm();
417 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
418 
419     default:
420         TCU_THROW(NotSupportedError, "WSI type not supported");
421     }
422 }
hasDisplay(vk::wsi::Type wsiType) const423 bool VulkanPlatform::hasDisplay(vk::wsi::Type wsiType) const
424 {
425     switch (wsiType)
426     {
427 #if defined(DEQP_SUPPORT_X11)
428     case vk::wsi::TYPE_XLIB:
429         return x11::XlibDisplay::hasDisplay(X11_DISPLAY);
430 #endif // DEQP_SUPPORT_X11
431 #if defined(DEQP_SUPPORT_XCB)
432     case vk::wsi::TYPE_XCB:
433         return x11::XcbDisplay::hasDisplay(X11_DISPLAY);
434 #endif // DEQP_SUPPORT_XCB
435 #if defined(DEQP_SUPPORT_WAYLAND)
436     case vk::wsi::TYPE_WAYLAND:
437         return wayland::Display::hasDisplay(WAYLAND_DISPLAY);
438 #endif // DEQP_SUPPORT_WAYLAND
439 #if defined(DEQP_SUPPORT_HEADLESS)
440     case vk::wsi::TYPE_HEADLESS:
441         return true;
442 #endif // DEQP_SUPPORT_HEADLESS
443 #if DEQP_SUPPORT_DRM && !defined(CTS_USES_VULKANSC)
444     case vk::wsi::TYPE_DIRECT_DRM:
445         return true;
446 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
447     default:
448         return false;
449     }
450 }
451 
createLibrary(LibraryType libraryType,const char * libraryPath) const452 vk::Library *VulkanPlatform::createLibrary(LibraryType libraryType, const char *libraryPath) const
453 {
454     switch (libraryType)
455     {
456     case LIBRARY_TYPE_VULKAN:
457         return new VulkanLibrary(libraryPath);
458 
459     default:
460         TCU_THROW(InternalError, "Unknown library type requested");
461     }
462 }
463 
describePlatform(std::ostream & dst) const464 void VulkanPlatform::describePlatform(std::ostream &dst) const
465 {
466     utsname sysInfo;
467     deMemset(&sysInfo, 0, sizeof(sysInfo));
468 
469     if (uname(&sysInfo) != 0)
470         throw std::runtime_error("uname() failed");
471 
472     dst << "OS: " << sysInfo.sysname << " " << sysInfo.release << " " << sysInfo.version << "\n";
473     dst << "CPU: " << sysInfo.machine << "\n";
474 }
475 
476 } // namespace lnx
477 } // namespace tcu
478