• 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 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