xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/wsi/vktWsiAcquireDrmDisplayTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 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 Vulkan coverage tests for extension VK_EXT_acquire_drm_display
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktWsiAcquireDrmDisplayTests.hpp"
25 
26 #include "vktCustomInstancesDevices.hpp"
27 #include "vktTestCase.hpp"
28 #include "vkDeviceUtil.hpp"
29 #include "vkQueryUtil.hpp"
30 
31 #include "tcuDefs.hpp"
32 #include "tcuLibDrm.hpp"
33 
34 #if DEQP_SUPPORT_DRM && !defined(CTS_USES_VULKANSC)
35 #include <fcntl.h>
36 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
37 
38 #include <string>
39 #include <vector>
40 
41 #if (DE_OS != DE_OS_WIN32)
42 #include <unistd.h>
43 #endif
44 
45 namespace vkt
46 {
47 namespace wsi
48 {
49 using namespace vk;
50 using std::string;
51 using std::vector;
52 #if DEQP_SUPPORT_DRM && !defined(CTS_USES_VULKANSC)
53 using tcu::LibDrm;
54 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
55 
56 #define INVALID_PTR 0xFFFFFFFF
57 
58 enum DrmTestIndex
59 {
60     DRM_TEST_INDEX_START,
61     DRM_TEST_INDEX_GET_DRM_DISPLAY,
62     DRM_TEST_INDEX_GET_DRM_DISPLAY_INVALID_FD,
63     DRM_TEST_INDEX_GET_DRM_DISPLAY_INVALID_CONNECTOR_ID,
64     DRM_TEST_INDEX_GET_DRM_DISPLAY_NOT_MASTER,
65     DRM_TEST_INDEX_GET_DRM_DISPLAY_UNOWNED_CONNECTOR_ID,
66     DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY,
67     DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY_INVALID_FD,
68     DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY_NOT_MASTER,
69     DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY_UNOWNED_CONNECTOR_ID,
70     DRM_TEST_INDEX_RELEASE_DISPLAY,
71     DRM_TEST_INDEX_LAST
72 };
73 
74 /*--------------------------------------------------------------------*//*!
75  * \brief Vulkan VK_EXT_acquire_drm_display extension tests
76  *//*--------------------------------------------------------------------*/
77 class AcquireDrmDisplayTestInstance : public TestInstance
78 {
79 public:
80     AcquireDrmDisplayTestInstance(Context &context, const DrmTestIndex testId);
81     tcu::TestStatus iterate(void) override;
82 
83 private:
84     CustomInstance createInstanceWithAcquireDrmDisplay(void);
85 
86 #if DEQP_SUPPORT_DRM && !defined(CTS_USES_VULKANSC)
87     LibDrm::FdPtr getDrmFdPtr(void);
88     uint32_t getConnectedConnectorId(int fd, uint32_t connectorId = 0);
89     uint32_t getValidCrtcId(int fd, uint32_t connectorId);
90     bool isDrmMaster(int fd);
91 
92     // VK_EXT_acquire_drm_display extension tests
93     tcu::TestStatus testGetDrmDisplayEXT(void);
94     tcu::TestStatus testGetDrmDisplayEXTInvalidFd(void);
95     tcu::TestStatus testGetDrmDisplayEXTInvalidConnectorId(void);
96     tcu::TestStatus testGetDrmDisplayEXTNotMaster(void);
97     tcu::TestStatus testGetDrmDisplayEXTUnownedConnectorId(void);
98     tcu::TestStatus testAcquireDrmDisplayEXT(void);
99     tcu::TestStatus testAcquireDrmDisplayEXTInvalidFd(void);
100     tcu::TestStatus testAcquireDrmDisplayEXTNotMaster(void);
101     tcu::TestStatus testAcquireDrmDisplayEXTUnownedConnectorId(void);
102     tcu::TestStatus testReleaseDisplayEXT(void);
103 
104     const LibDrm m_libDrm;
105 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
106 
107     const CustomInstance m_instance;
108     const InstanceInterface &m_vki;
109     const VkPhysicalDevice m_physDevice;
110     const DrmTestIndex m_testId;
111 };
112 
113 /*--------------------------------------------------------------------*//*!
114  * \brief AcquireDrmDisplayTestInstance constructor
115  *
116  * Initializes AcquireDrmDisplayTestInstance object
117  *
118  * \param context    Context object
119  * \param testId    Enum for which test to run
120  *//*--------------------------------------------------------------------*/
AcquireDrmDisplayTestInstance(Context & context,const DrmTestIndex testId)121 AcquireDrmDisplayTestInstance::AcquireDrmDisplayTestInstance(Context &context, const DrmTestIndex testId)
122     : TestInstance(context)
123     , m_instance(createInstanceWithAcquireDrmDisplay())
124     , m_vki(m_instance.getDriver())
125     , m_physDevice(vk::chooseDevice(m_vki, m_instance, context.getTestContext().getCommandLine()))
126     , m_testId(testId)
127 {
128     DE_UNREF(m_testId);
129 }
130 
131 /*--------------------------------------------------------------------*//*!
132  * \brief Step forward test execution
133  *
134  * \return true if application should call iterate() again and false
135  *         if test execution session is complete.
136  *//*--------------------------------------------------------------------*/
iterate(void)137 tcu::TestStatus AcquireDrmDisplayTestInstance::iterate(void)
138 {
139 #if DEQP_SUPPORT_DRM && !defined(CTS_USES_VULKANSC)
140     switch (m_testId)
141     {
142     case DRM_TEST_INDEX_GET_DRM_DISPLAY:
143         return testGetDrmDisplayEXT();
144     case DRM_TEST_INDEX_GET_DRM_DISPLAY_INVALID_FD:
145         return testGetDrmDisplayEXTInvalidFd();
146     case DRM_TEST_INDEX_GET_DRM_DISPLAY_INVALID_CONNECTOR_ID:
147         return testGetDrmDisplayEXTInvalidConnectorId();
148     case DRM_TEST_INDEX_GET_DRM_DISPLAY_NOT_MASTER:
149         return testGetDrmDisplayEXTNotMaster();
150     case DRM_TEST_INDEX_GET_DRM_DISPLAY_UNOWNED_CONNECTOR_ID:
151         return testGetDrmDisplayEXTUnownedConnectorId();
152     case DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY:
153         return testAcquireDrmDisplayEXT();
154     case DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY_INVALID_FD:
155         return testAcquireDrmDisplayEXTInvalidFd();
156     case DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY_NOT_MASTER:
157         return testAcquireDrmDisplayEXTNotMaster();
158     case DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY_UNOWNED_CONNECTOR_ID:
159         return testAcquireDrmDisplayEXTUnownedConnectorId();
160     case DRM_TEST_INDEX_RELEASE_DISPLAY:
161         return testReleaseDisplayEXT();
162     default:
163     {
164         DE_FATAL("Impossible");
165     }
166     }
167 
168     TCU_FAIL("Invalid test identifier");
169 #else
170     TCU_THROW(NotSupportedError, "Drm not supported.");
171 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
172 }
173 
174 // /*--------------------------------------------------------------------*//*!
175 //  * \brief Create a instance with the VK_EXT_acquire_drm_display extension.
176 //  *
177 //  * \return The created instance
178 //  *//*--------------------------------------------------------------------*/
createInstanceWithAcquireDrmDisplay(void)179 CustomInstance AcquireDrmDisplayTestInstance::createInstanceWithAcquireDrmDisplay(void)
180 {
181     vector<VkExtensionProperties> supportedExtensions =
182         enumerateInstanceExtensionProperties(m_context.getPlatformInterface(), DE_NULL);
183     vector<string> requiredExtensions = {
184         "VK_EXT_acquire_drm_display",
185         "VK_EXT_direct_mode_display",
186     };
187 
188     for (const auto &extension : requiredExtensions)
189         if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(extension)))
190             TCU_THROW(NotSupportedError, "Instance extension not supported.");
191 
192     return createCustomInstanceWithExtensions(m_context, requiredExtensions);
193 }
194 
195 #if DEQP_SUPPORT_DRM && !defined(CTS_USES_VULKANSC)
196 // /*--------------------------------------------------------------------*//*!
197 //  * \brief Open a fd for the Drm corresponding to the Vulkan instance
198 //  *
199 //  * \return A LibDrm::FdPtr with the int fd.
200 //  *//*--------------------------------------------------------------------*/
getDrmFdPtr(void)201 LibDrm::FdPtr AcquireDrmDisplayTestInstance::getDrmFdPtr(void)
202 {
203     VkPhysicalDeviceProperties2 deviceProperties2;
204     VkPhysicalDeviceDrmPropertiesEXT deviceDrmProperties;
205 
206     deMemset(&deviceDrmProperties, 0, sizeof(deviceDrmProperties));
207     deviceDrmProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT;
208     deviceDrmProperties.pNext = DE_NULL;
209 
210     deMemset(&deviceProperties2, 0, sizeof(deviceProperties2));
211     deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
212     deviceProperties2.pNext = &deviceDrmProperties;
213 
214     m_vki.getPhysicalDeviceProperties2(m_physDevice, &deviceProperties2);
215 
216     if (!deviceDrmProperties.hasPrimary)
217         TCU_THROW(NotSupportedError, "No DRM primary device.");
218 
219     int numDrmDevices;
220     drmDevicePtr *drmDevices = m_libDrm.getDevices(&numDrmDevices);
221     const char *drmNode      = m_libDrm.findDeviceNode(drmDevices, numDrmDevices, deviceDrmProperties.primaryMajor,
222                                                        deviceDrmProperties.primaryMinor);
223 
224     if (!drmNode)
225         TCU_THROW(NotSupportedError, "No DRM node.");
226 
227     return m_libDrm.openFd(drmNode);
228 }
229 
230 /*--------------------------------------------------------------------*//*!
231  * \brief Get a connected Drm connector
232  *
233  * \param fd            A Drm fd to query
234  * \param connectorId    If nonzero, a connector to be different from
235  * \return The connectorId of the connected Drm connector
236  *//*--------------------------------------------------------------------*/
getConnectedConnectorId(int fd,uint32_t connectorId)237 uint32_t AcquireDrmDisplayTestInstance::getConnectedConnectorId(int fd, uint32_t connectorId)
238 {
239     LibDrm::ResPtr res = m_libDrm.getResources(fd);
240     if (!res)
241         TCU_THROW(NotSupportedError, "Could not get DRM resources.");
242 
243     for (int i = 0; i < res->count_connectors; ++i)
244     {
245         if (connectorId && connectorId == res->connectors[i])
246             continue;
247         LibDrm::ConnectorPtr conn = m_libDrm.getConnector(fd, res->connectors[i]);
248 
249         if (conn && conn->connection == DRM_MODE_CONNECTED)
250         {
251             return res->connectors[i];
252         }
253     }
254     return 0;
255 }
256 
257 /*--------------------------------------------------------------------*//*!
258  * \brief Get a valid Drm crtc for the connector
259  *
260  * \param fd            A Drm fd to query
261  * \param connectorId    The connector that the crtc is valid for
262  * \return The crtcId of the valid Drm crtc
263  *//*--------------------------------------------------------------------*/
getValidCrtcId(int fd,uint32_t connectorId)264 uint32_t AcquireDrmDisplayTestInstance::getValidCrtcId(int fd, uint32_t connectorId)
265 {
266     LibDrm::ResPtr res        = m_libDrm.getResources(fd);
267     LibDrm::ConnectorPtr conn = m_libDrm.getConnector(fd, connectorId);
268     if (!res || !conn)
269         TCU_THROW(NotSupportedError, "Could not get DRM resources or connector.");
270 
271     for (int i = 0; i < conn->count_encoders; ++i)
272     {
273         LibDrm::EncoderPtr enc = m_libDrm.getEncoder(fd, conn->encoders[i]);
274         if (!enc)
275             continue;
276 
277         for (int j = 0; j < res->count_crtcs; ++j)
278             if (enc->possible_crtcs & (1 << j))
279                 return res->crtcs[j];
280     }
281     return 0;
282 }
283 
284 /*--------------------------------------------------------------------*//*!
285  * \brief Checks if we have Drm master permissions
286  *
287  * \param fd A Drm fd to query
288  * \return True if we have Drm master
289  *//*--------------------------------------------------------------------*/
isDrmMaster(int fd)290 bool AcquireDrmDisplayTestInstance::isDrmMaster(int fd)
291 {
292     /*
293      * Call a drm API that requires master permissions, but with an invalid
294      * value. If we are master it should return -EINVAL, but if we are not
295      * it should return -EACCESS.
296      */
297     return m_libDrm.authMagic(fd, 0) != -EACCES;
298 }
299 
300 // /*--------------------------------------------------------------------*//*!
301 //  * \brief Tests successfully getting a connected Drm display
302 //  *
303 //  * Throws an exception on fail.
304 //  *
305 //  * \return tcu::TestStatus::pass on success
306 //  *//*--------------------------------------------------------------------*/
testGetDrmDisplayEXT(void)307 tcu::TestStatus AcquireDrmDisplayTestInstance::testGetDrmDisplayEXT(void)
308 {
309     LibDrm::FdPtr fdPtr = getDrmFdPtr();
310     if (!fdPtr)
311         TCU_THROW(NotSupportedError, "Could not open DRM.");
312     int fd = *fdPtr;
313 
314     uint32_t connectorId = getConnectedConnectorId(fd);
315     if (!connectorId)
316         TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
317 
318     VkDisplayKHR display = INVALID_PTR;
319     VkResult result      = m_vki.getDrmDisplayEXT(m_physDevice, fd, connectorId, &display);
320     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
321         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
322 
323     if (result != VK_SUCCESS)
324         TCU_FAIL("vkGetDrmDisplayEXT failed.");
325 
326     if (display == DE_NULL || display == INVALID_PTR)
327         TCU_FAIL("vkGetDrmDisplayEXT did not set display.");
328 
329     return tcu::TestStatus::pass("pass");
330 }
331 
332 // /*--------------------------------------------------------------------*//*!
333 //  * \brief Tests getting an error with an invalid Drm fd
334 //  *
335 //  * Throws an exception on fail.
336 //  *
337 //  * \return tcu::TestStatus::pass on success
338 //  *//*--------------------------------------------------------------------*/
testGetDrmDisplayEXTInvalidFd(void)339 tcu::TestStatus AcquireDrmDisplayTestInstance::testGetDrmDisplayEXTInvalidFd(void)
340 {
341     LibDrm::FdPtr fdPtr = getDrmFdPtr();
342     if (!fdPtr)
343         TCU_THROW(NotSupportedError, "Could not open DRM.");
344     int fd = *fdPtr;
345 
346     uint32_t connectorId = getConnectedConnectorId(fd);
347     if (!connectorId)
348         TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
349 
350     int invalidFd        = open("/", O_RDONLY | O_PATH);
351     VkDisplayKHR display = INVALID_PTR;
352     VkResult result      = m_vki.getDrmDisplayEXT(m_physDevice, invalidFd, connectorId, &display);
353     close(invalidFd);
354     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
355         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
356 
357     if (result != VK_ERROR_UNKNOWN)
358         TCU_FAIL("vkGetDrmDisplayEXT failed to return error.");
359 
360     return tcu::TestStatus::pass("pass");
361 }
362 
363 // /*--------------------------------------------------------------------*//*!
364 //  * \brief Tests getting an error with an invalid connector id
365 //  *
366 //  * Throws an exception on fail.
367 //  *
368 //  * \return tcu::TestStatus::pass on success
369 //  *//*--------------------------------------------------------------------*/
testGetDrmDisplayEXTInvalidConnectorId(void)370 tcu::TestStatus AcquireDrmDisplayTestInstance::testGetDrmDisplayEXTInvalidConnectorId(void)
371 {
372     LibDrm::FdPtr fdPtr = getDrmFdPtr();
373     if (!fdPtr)
374         TCU_THROW(NotSupportedError, "Could not open DRM.");
375     int fd = *fdPtr;
376 
377     uint32_t connectorId = getConnectedConnectorId(fd);
378     if (!connectorId)
379         TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
380 
381     uint32_t invalidConnectorId = connectorId + 1234;
382     VkDisplayKHR display        = INVALID_PTR;
383     VkResult result             = m_vki.getDrmDisplayEXT(m_physDevice, fd, invalidConnectorId, &display);
384     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
385         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
386 
387     if (result != VK_ERROR_UNKNOWN)
388         TCU_FAIL("vkGetDrmDisplayEXT failed to return error.");
389 
390     if (display != DE_NULL)
391         TCU_FAIL("vkGetDrmDisplayEXT did not set display to null.");
392 
393     return tcu::TestStatus::pass("pass");
394 }
395 
396 // /*--------------------------------------------------------------------*//*!
397 //  * \brief Tests successfully getting without master
398 //  *
399 //  * Throws an exception on fail.
400 //  *
401 //  * \return tcu::TestStatus::pass on success
402 //  *//*--------------------------------------------------------------------*/
testGetDrmDisplayEXTNotMaster(void)403 tcu::TestStatus AcquireDrmDisplayTestInstance::testGetDrmDisplayEXTNotMaster(void)
404 {
405     LibDrm::FdPtr masterFdPtr    = getDrmFdPtr();
406     LibDrm::FdPtr notMasterFdPtr = getDrmFdPtr();
407     if (!masterFdPtr || !notMasterFdPtr)
408         TCU_THROW(NotSupportedError, "Could not open DRM.");
409     if (*masterFdPtr == *notMasterFdPtr)
410         TCU_THROW(NotSupportedError, "Did not open 2 different fd.");
411     int fd = *notMasterFdPtr;
412 
413     uint32_t connectorId = getConnectedConnectorId(fd);
414     if (!connectorId)
415         TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
416 
417     VkDisplayKHR display = INVALID_PTR;
418     VkResult result      = m_vki.getDrmDisplayEXT(m_physDevice, fd, connectorId, &display);
419     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
420         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
421 
422     if (result != VK_SUCCESS)
423         TCU_FAIL("vkGetDrmDisplayEXT failed.");
424 
425     if (display == DE_NULL || display == INVALID_PTR)
426         TCU_FAIL("vkGetDrmDisplayEXT did not set display.");
427 
428     return tcu::TestStatus::pass("pass");
429 }
430 
431 // /*--------------------------------------------------------------------*//*!
432 //  * \brief Tests getting an error with an unowned connector id
433 //  *
434 //  * This needs to be run with drm master permissions.
435 //  * No other drm client can be running, such as X or Wayland.
436 //  * Then, to run with drm master, either:
437 //  *   Add your user to the "video" linux group.
438 //  *   Log in to the virtual tty.
439 //  *   Run as root.
440 //  * This also requires 2 physically connected displays.
441 //  *
442 //  * Throws an exception on fail.
443 //  *
444 //  * \return tcu::TestStatus::pass on success
445 //  *//*--------------------------------------------------------------------*/
testGetDrmDisplayEXTUnownedConnectorId(void)446 tcu::TestStatus AcquireDrmDisplayTestInstance::testGetDrmDisplayEXTUnownedConnectorId(void)
447 {
448     LibDrm::FdPtr fdPtr = getDrmFdPtr();
449     if (!fdPtr)
450         TCU_THROW(NotSupportedError, "Could not open DRM.");
451     int fd = *fdPtr;
452 
453     if (!isDrmMaster(fd))
454         TCU_THROW(NotSupportedError, "Does not have drm master permissions.");
455 
456     uint32_t connectorId      = getConnectedConnectorId(fd);
457     uint32_t otherConnectorId = getConnectedConnectorId(fd, connectorId);
458     uint32_t crtcId           = getValidCrtcId(fd, connectorId);
459     if (!connectorId || !crtcId || !otherConnectorId || connectorId == otherConnectorId)
460         TCU_THROW(NotSupportedError, "Could not find 2 DRM connectors or a crtc.");
461 
462     // Lease the first connector, but try to get the other connector.
463     uint32_t objects[2]      = {connectorId, crtcId};
464     LibDrm::FdPtr leaseFdPtr = m_libDrm.createLease(fd, objects, 2, O_CLOEXEC);
465     if (!leaseFdPtr)
466         TCU_THROW(NotSupportedError, "Could not lease DRM.");
467     int leaseFd = *leaseFdPtr;
468 
469     VkDisplayKHR display = INVALID_PTR;
470     VkResult result      = m_vki.getDrmDisplayEXT(m_physDevice, leaseFd, otherConnectorId, &display);
471     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
472         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
473 
474     if (result != VK_ERROR_UNKNOWN)
475         TCU_FAIL("vkGetDrmDisplayEXT failed to return error.");
476 
477     if (display != DE_NULL)
478         TCU_FAIL("vkGetDrmDisplayEXT did not set display to null.");
479 
480     return tcu::TestStatus::pass("pass");
481 }
482 
483 // /*--------------------------------------------------------------------*//*!
484 //  * \brief Tests successfully acquiring a connected Drm display
485 //  *
486 //  * This needs to be run with drm master permissions.
487 //  * No other drm client can be running, such as X or Wayland.
488 //  * Then, to run with drm master, either:
489 //  *   Add your user to the "video" linux group.
490 //  *   Log in to the virtual tty.
491 //  *   Run as root.
492 //  *
493 //  * Throws an exception on fail.
494 //  *
495 //  * \return tcu::TestStatus::pass on success
496 //  *//*--------------------------------------------------------------------*/
testAcquireDrmDisplayEXT(void)497 tcu::TestStatus AcquireDrmDisplayTestInstance::testAcquireDrmDisplayEXT(void)
498 {
499     LibDrm::FdPtr fdPtr = getDrmFdPtr();
500     if (!fdPtr)
501         TCU_THROW(NotSupportedError, "Could not open DRM.");
502     int fd = *fdPtr;
503 
504     if (!isDrmMaster(fd))
505         TCU_THROW(NotSupportedError, "Does not have drm master permissions.");
506 
507     uint32_t connectorId = getConnectedConnectorId(fd);
508     if (!connectorId)
509         TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
510 
511     VkDisplayKHR display = INVALID_PTR;
512     VkResult result      = m_vki.getDrmDisplayEXT(m_physDevice, fd, connectorId, &display);
513     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
514         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
515 
516     if (result != VK_SUCCESS)
517         TCU_FAIL("vkGetDrmDisplayEXT failed.");
518 
519     if (display == DE_NULL || display == INVALID_PTR)
520         TCU_FAIL("vkGetDrmDisplayEXT did not set display.");
521 
522     result = m_vki.acquireDrmDisplayEXT(m_physDevice, fd, display);
523     if (result != VK_SUCCESS)
524         TCU_FAIL("vkAcquireDrmDisplayEXT failed.");
525 
526     return tcu::TestStatus::pass("pass");
527 }
528 
529 // /*--------------------------------------------------------------------*//*!
530 //  * \brief Tests getting an error with an invalid drm fd
531 //  *
532 //  * Throws an exception on fail.
533 //  *
534 //  * \return tcu::TestStatus::pass on success
535 //  *//*--------------------------------------------------------------------*/
testAcquireDrmDisplayEXTInvalidFd(void)536 tcu::TestStatus AcquireDrmDisplayTestInstance::testAcquireDrmDisplayEXTInvalidFd(void)
537 {
538     LibDrm::FdPtr fdPtr = getDrmFdPtr();
539     if (!fdPtr)
540         TCU_THROW(NotSupportedError, "Could not open DRM.");
541     int fd = *fdPtr;
542 
543     uint32_t connectorId = getConnectedConnectorId(fd);
544     if (!connectorId)
545         TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
546 
547     VkDisplayKHR display = INVALID_PTR;
548     VkResult result      = m_vki.getDrmDisplayEXT(m_physDevice, fd, connectorId, &display);
549     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
550         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
551 
552     if (result != VK_SUCCESS)
553         TCU_FAIL("vkGetDrmDisplayEXT failed.");
554 
555     if (display == DE_NULL || display == INVALID_PTR)
556         TCU_FAIL("vkGetDrmDisplayEXT did not set display.");
557 
558     int invalidFd = open("/", O_RDONLY | O_PATH);
559     result        = m_vki.acquireDrmDisplayEXT(m_physDevice, invalidFd, display);
560     close(invalidFd);
561     if (result != VK_ERROR_UNKNOWN)
562         TCU_FAIL("vkAcquireDrmDisplayEXT failed to return error.");
563 
564     return tcu::TestStatus::pass("pass");
565 }
566 
567 // /*--------------------------------------------------------------------*//*!
568 //  * \brief Tests getting an error without master
569 //  *
570 //  * Throws an exception on fail.
571 //  *
572 //  * \return tcu::TestStatus::pass on success
573 //  *//*--------------------------------------------------------------------*/
testAcquireDrmDisplayEXTNotMaster(void)574 tcu::TestStatus AcquireDrmDisplayTestInstance::testAcquireDrmDisplayEXTNotMaster(void)
575 {
576     LibDrm::FdPtr masterFdPtr    = getDrmFdPtr();
577     LibDrm::FdPtr notMasterFdPtr = getDrmFdPtr();
578     if (!masterFdPtr || !notMasterFdPtr)
579         TCU_THROW(NotSupportedError, "Could not open DRM.");
580     if (*masterFdPtr == *notMasterFdPtr)
581         TCU_THROW(NotSupportedError, "Did not open 2 different fd.");
582     int fd = *notMasterFdPtr;
583 
584     uint32_t connectorId = getConnectedConnectorId(fd);
585     if (!connectorId)
586         TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
587 
588     VkDisplayKHR display = INVALID_PTR;
589     VkResult result      = m_vki.getDrmDisplayEXT(m_physDevice, fd, connectorId, &display);
590     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
591         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
592 
593     if (result != VK_SUCCESS)
594         TCU_FAIL("vkGetDrmDisplayEXT failed.");
595 
596     if (display == DE_NULL || display == INVALID_PTR)
597         TCU_FAIL("vkGetDrmDisplayEXT did not set display.");
598 
599     result = m_vki.acquireDrmDisplayEXT(m_physDevice, fd, display);
600     if (result != VK_ERROR_INITIALIZATION_FAILED)
601         TCU_FAIL("vkAcquireDrmDisplayEXT failed to return error.");
602 
603     return tcu::TestStatus::pass("pass");
604 }
605 
606 // /*--------------------------------------------------------------------*//*!
607 //  * \brief Tests getting an error with an unowned connector id
608 //  *
609 //  * This needs to be run with drm master permissions.
610 //  * No other drm client can be running, such as X or Wayland.
611 //  * Then, to run with drm master, either:
612 //  *   Add your user to the "video" linux group.
613 //  *   Log in to the virtual tty.
614 //  *   Run as root.
615 //  * This also requires 2 physically connected displays.
616 //  *
617 //  * Throws an exception on fail.
618 //  *
619 //  * \return tcu::TestStatus::pass on success
620 //  *//*--------------------------------------------------------------------*/
testAcquireDrmDisplayEXTUnownedConnectorId(void)621 tcu::TestStatus AcquireDrmDisplayTestInstance::testAcquireDrmDisplayEXTUnownedConnectorId(void)
622 {
623     LibDrm::FdPtr fdPtr = getDrmFdPtr();
624     if (!fdPtr)
625         TCU_THROW(NotSupportedError, "Could not open DRM.");
626     int fd = *fdPtr;
627 
628     if (!isDrmMaster(fd))
629         TCU_THROW(NotSupportedError, "Does not have drm master permissions.");
630 
631     uint32_t connectorId      = getConnectedConnectorId(fd);
632     uint32_t otherConnectorId = getConnectedConnectorId(fd, connectorId);
633     uint32_t crtcId           = getValidCrtcId(fd, connectorId);
634     if (!connectorId || !crtcId || !otherConnectorId || connectorId == otherConnectorId)
635         TCU_THROW(NotSupportedError, "Could not find 2 DRM connectors or a crtc.");
636 
637     // Lease the first connector, but try to get and acquire the other connector.
638     uint32_t objects[2]      = {connectorId, crtcId};
639     LibDrm::FdPtr leaseFdPtr = m_libDrm.createLease(fd, objects, 2, O_CLOEXEC);
640     if (!leaseFdPtr)
641         TCU_THROW(NotSupportedError, "Could not lease DRM.");
642     int leaseFd = *leaseFdPtr;
643 
644     // We know that this would fail with leaseFd, so use the original master fd.
645     VkDisplayKHR display = INVALID_PTR;
646     VkResult result      = m_vki.getDrmDisplayEXT(m_physDevice, fd, otherConnectorId, &display);
647     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
648         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
649 
650     if (result != VK_SUCCESS)
651         TCU_FAIL("vkGetDrmDisplayEXT failed.");
652 
653     if (display == DE_NULL || display == INVALID_PTR)
654         TCU_FAIL("vkGetDrmDisplayEXT did not set display.");
655 
656     result = m_vki.acquireDrmDisplayEXT(m_physDevice, leaseFd, display);
657     if (result != VK_ERROR_INITIALIZATION_FAILED)
658         TCU_FAIL("vkAcquireDrmDisplayEXT failed to return error.");
659 
660     return tcu::TestStatus::pass("pass");
661 }
662 
663 // /*--------------------------------------------------------------------*//*!
664 //  * \brief Tests successfully releasing an acquired Drm display
665 //  *
666 //  * This needs to be run with drm master permissions.
667 //  * No other drm client can be running, such as X or Wayland.
668 //  * Then, to run with drm master, either:
669 //  *   Add your user to the "video" linux group.
670 //  *   Log in to the virtual tty.
671 //  *   Run as root.
672 //  *
673 //  * Throws an exception on fail.
674 //  *
675 //  * \return tcu::TestStatus::pass on success
676 //  *//*--------------------------------------------------------------------*/
testReleaseDisplayEXT(void)677 tcu::TestStatus AcquireDrmDisplayTestInstance::testReleaseDisplayEXT(void)
678 {
679     LibDrm::FdPtr fdPtr = getDrmFdPtr();
680     if (!fdPtr)
681         TCU_THROW(NotSupportedError, "Could not open DRM.");
682     int fd = *fdPtr;
683 
684     if (!isDrmMaster(fd))
685         TCU_THROW(NotSupportedError, "Does not have drm master permissions.");
686 
687     uint32_t connectorId = getConnectedConnectorId(fd);
688     if (!connectorId)
689         TCU_THROW(NotSupportedError, "Could not find a DRM connector.");
690 
691     VkDisplayKHR display = INVALID_PTR;
692     VkResult result      = m_vki.getDrmDisplayEXT(m_physDevice, fd, connectorId, &display);
693     if (result == VK_ERROR_EXTENSION_NOT_PRESENT)
694         TCU_THROW(NotSupportedError, "VK_EXT_acquire_drm_display not supported.");
695 
696     if (result != VK_SUCCESS)
697         TCU_FAIL("vkGetDrmDisplayEXT failed.");
698 
699     if (display == DE_NULL || display == INVALID_PTR)
700         TCU_FAIL("vkGetDrmDisplayEXT did not set display.");
701 
702     result = m_vki.acquireDrmDisplayEXT(m_physDevice, fd, display);
703     if (result != VK_SUCCESS)
704         TCU_FAIL("vkAcquireDrmDisplayEXT failed.");
705 
706     result = m_vki.releaseDisplayEXT(m_physDevice, display);
707     if (result != VK_SUCCESS)
708         TCU_FAIL("vkReleaseDisplayEXT failed.");
709 
710     return tcu::TestStatus::pass("pass");
711 }
712 #endif // DEQP_SUPPORT_DRM && !defined (CTS_USES_VULKANSC)
713 
714 /*--------------------------------------------------------------------*//*!
715  * \brief Acquire Drm display tests case class
716  *//*--------------------------------------------------------------------*/
717 class AcquireDrmDisplayTestsCase : public vkt::TestCase
718 {
719 public:
AcquireDrmDisplayTestsCase(tcu::TestContext & context,const char * name,const DrmTestIndex testId)720     AcquireDrmDisplayTestsCase(tcu::TestContext &context, const char *name, const DrmTestIndex testId)
721         : TestCase(context, name)
722         , m_testId(testId)
723     {
724     }
725 
726 private:
727     const DrmTestIndex m_testId;
728 
createInstance(vkt::Context & context) const729     vkt::TestInstance *createInstance(vkt::Context &context) const
730     {
731         return new AcquireDrmDisplayTestInstance(context, m_testId);
732     }
733 };
734 
735 /*--------------------------------------------------------------------*//*!
736  * \brief Adds a test into group
737  *//*--------------------------------------------------------------------*/
addTest(tcu::TestCaseGroup * group,const DrmTestIndex testId,const char * name)738 static void addTest(tcu::TestCaseGroup *group, const DrmTestIndex testId, const char *name)
739 {
740     tcu::TestContext &testCtx = group->getTestContext();
741 
742     group->addChild(new AcquireDrmDisplayTestsCase(testCtx, name, testId));
743 }
744 
745 /*--------------------------------------------------------------------*//*!
746  * \brief Adds VK_EXT_acquire_drm_display extension tests into group
747  *//*--------------------------------------------------------------------*/
createAcquireDrmDisplayTests(tcu::TestCaseGroup * group)748 void createAcquireDrmDisplayTests(tcu::TestCaseGroup *group)
749 {
750     // VK_EXT_acquire_drm_display extension tests
751     // Get Drm display test
752     addTest(group, DRM_TEST_INDEX_GET_DRM_DISPLAY, "get_drm_display");
753     // Get Drm display with invalid fd test
754     addTest(group, DRM_TEST_INDEX_GET_DRM_DISPLAY_INVALID_FD, "get_drm_display_invalid_fd");
755     // Get Drm display with invalid connector id test
756     addTest(group, DRM_TEST_INDEX_GET_DRM_DISPLAY_INVALID_CONNECTOR_ID, "get_drm_display_invalid_connector_id");
757     // Get Drm display with not master test
758     addTest(group, DRM_TEST_INDEX_GET_DRM_DISPLAY_NOT_MASTER, "get_drm_display_not_master");
759     // Get Drm display with unowned connector id test
760     addTest(group, DRM_TEST_INDEX_GET_DRM_DISPLAY_UNOWNED_CONNECTOR_ID, "get_drm_display_unowned_connector_id");
761     // Acquire Drm display test
762     addTest(group, DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY, "acquire_drm_display");
763     // Acquire Drm display with invalid fd test
764     addTest(group, DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY_INVALID_FD, "acquire_drm_display_invalid_fd");
765     // Acquire Drm display with not master test
766     addTest(group, DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY_NOT_MASTER, "acquire_drm_display_not_master");
767     // Acquire Drm display with unowned connector id test
768     addTest(group, DRM_TEST_INDEX_ACQUIRE_DRM_DISPLAY_UNOWNED_CONNECTOR_ID, "acquire_drm_display_unowned_connector_id");
769 
770     // VK_EXT_direct_mode_display extension tests
771     // Release Drm display test
772     addTest(group, DRM_TEST_INDEX_RELEASE_DISPLAY, "release_display");
773 }
774 
775 } // namespace wsi
776 } // namespace vkt
777