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