• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "DisplaySurfaceKHR.hpp"
16 
17 #include "Vulkan/VkDeviceMemory.hpp"
18 #include "Vulkan/VkImage.hpp"
19 
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <sys/mman.h>
24 #include <unistd.h>
25 #include <xf86drm.h>
26 
27 namespace vk {
28 
openCard()29 static int openCard()
30 {
31 	constexpr size_t DIR_NAME_MAX = sizeof("/dev/dri/") - 1;
32 	constexpr size_t PRE_NODE_NAME_MAX = sizeof("card") - 1;
33 	constexpr size_t POST_NODE_NAME_MAX = sizeof("255") - 1;
34 	constexpr size_t NODE_NAME_MAX =
35 	    DIR_NAME_MAX + PRE_NODE_NAME_MAX + POST_NODE_NAME_MAX;
36 	char name[NODE_NAME_MAX] = "/dev/dri/";
37 	int fd = -VK_NOT_READY;
38 
39 	/*
40 	 * Open the first DRM/KMS device. The libdrm drmOpen*() functions
41 	 * from drmOpen() is of no practical use as any modern system will
42 	 * handle that through udev or an equivalent component.
43 	 */
44 	DIR *folder = opendir(name);
45 	if(!folder)
46 	{
47 		return -errno;
48 	}
49 
50 	strncat(name, "card", 5);
51 	for(struct dirent *res; (res = readdir(folder));)
52 	{
53 		if(!strncmp(res->d_name, "card", 4))
54 		{
55 			strncat(name, res->d_name + PRE_NODE_NAME_MAX, 4);
56 			fd = open(name, O_RDWR);
57 			if(fd >= 0)
58 			{
59 				break;
60 			}
61 
62 			name[DIR_NAME_MAX + PRE_NODE_NAME_MAX] = 0;
63 			fd = -errno;
64 		}
65 	}
66 
67 	closedir(folder);
68 
69 	return fd;
70 }
71 
GetDisplayModeProperties(uint32_t * pPropertyCount,VkDisplayModePropertiesKHR * pProperties)72 VkResult DisplaySurfaceKHR::GetDisplayModeProperties(uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties)
73 {
74 	*pPropertyCount = 1;
75 
76 	if(pProperties)
77 	{
78 		const int fd = openCard();
79 		if(fd < 0)
80 		{
81 			return VK_NOT_READY;
82 		}
83 
84 		drmModeRes *res = drmModeGetResources(fd);
85 		drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[0]);
86 		pProperties->displayMode = (uintptr_t)connector->modes[0].name;
87 		pProperties->parameters.visibleRegion.width = connector->modes[0].hdisplay;
88 		pProperties->parameters.visibleRegion.height = connector->modes[0].vdisplay;
89 		pProperties->parameters.refreshRate = connector->modes[0].vrefresh * 1000;
90 		drmModeFreeConnector(connector);
91 		drmModeFreeResources(res);
92 		close(fd);
93 	}
94 
95 	return VK_SUCCESS;
96 }
97 
GetDisplayPlaneCapabilities(VkDisplayPlaneCapabilitiesKHR * pCapabilities)98 VkResult DisplaySurfaceKHR::GetDisplayPlaneCapabilities(VkDisplayPlaneCapabilitiesKHR *pCapabilities)
99 {
100 	const int fd = openCard();
101 	if(fd < 0)
102 	{
103 		return VK_NOT_READY;
104 	}
105 
106 	drmModeRes *res = drmModeGetResources(fd);
107 	drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[0]);
108 	pCapabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
109 	pCapabilities->minSrcPosition.x = 0;
110 	pCapabilities->minSrcPosition.y = 0;
111 	pCapabilities->maxSrcPosition.x = 0;
112 	pCapabilities->maxSrcPosition.y = 0;
113 	pCapabilities->minSrcExtent.width = connector->modes[0].hdisplay;
114 	pCapabilities->minSrcExtent.height = connector->modes[0].vdisplay;
115 	pCapabilities->maxSrcExtent.width = connector->modes[0].hdisplay;
116 	pCapabilities->maxSrcExtent.height = connector->modes[0].vdisplay;
117 	pCapabilities->minDstPosition.x = 0;
118 	pCapabilities->minDstPosition.y = 0;
119 	pCapabilities->maxDstPosition.x = 0;
120 	pCapabilities->maxDstPosition.y = 0;
121 	pCapabilities->minDstExtent.width = connector->modes[0].hdisplay;
122 	pCapabilities->minDstExtent.height = connector->modes[0].vdisplay;
123 	pCapabilities->maxDstExtent.width = connector->modes[0].hdisplay;
124 	pCapabilities->maxDstExtent.height = connector->modes[0].vdisplay;
125 	drmModeFreeConnector(connector);
126 	drmModeFreeResources(res);
127 	close(fd);
128 
129 	return VK_SUCCESS;
130 }
131 
GetDisplayPlaneSupportedDisplays(uint32_t * pDisplayCount,VkDisplayKHR * pDisplays)132 VkResult DisplaySurfaceKHR::GetDisplayPlaneSupportedDisplays(uint32_t *pDisplayCount, VkDisplayKHR *pDisplays)
133 {
134 	*pDisplayCount = 1;
135 
136 	if(pDisplays)
137 	{
138 		const int fd = openCard();
139 		if(fd < 0)
140 		{
141 			return VK_NOT_READY;
142 		}
143 
144 		drmModeRes *res = drmModeGetResources(fd);
145 		*pDisplays = res->connectors[0];
146 		drmModeFreeResources(res);
147 		close(fd);
148 	}
149 
150 	return VK_SUCCESS;
151 }
152 
GetPhysicalDeviceDisplayPlaneProperties(uint32_t * pPropertyCount,VkDisplayPlanePropertiesKHR * pProperties)153 VkResult DisplaySurfaceKHR::GetPhysicalDeviceDisplayPlaneProperties(uint32_t *pPropertyCount, VkDisplayPlanePropertiesKHR *pProperties)
154 {
155 	*pPropertyCount = 1;
156 
157 	if(pProperties)
158 	{
159 		const int fd = openCard();
160 		if(fd < 0)
161 		{
162 			return VK_NOT_READY;
163 		}
164 
165 		drmModeRes *res = drmModeGetResources(fd);
166 		pProperties->currentDisplay = res->connectors[0];
167 		pProperties->currentStackIndex = 0;
168 		drmModeFreeResources(res);
169 		close(fd);
170 	}
171 
172 	return VK_SUCCESS;
173 }
174 
GetPhysicalDeviceDisplayProperties(uint32_t * pPropertyCount,VkDisplayPropertiesKHR * pProperties)175 VkResult DisplaySurfaceKHR::GetPhysicalDeviceDisplayProperties(uint32_t *pPropertyCount, VkDisplayPropertiesKHR *pProperties)
176 {
177 	*pPropertyCount = 1;
178 
179 	if(pProperties)
180 	{
181 		const int fd = openCard();
182 		if(fd < 0)
183 		{
184 			return VK_NOT_READY;
185 		}
186 
187 		drmModeRes *res = drmModeGetResources(fd);
188 		drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[0]);
189 		pProperties->display = res->connectors[0];
190 		pProperties->displayName = "monitor";
191 		pProperties->physicalDimensions.width = connector->mmWidth;
192 		pProperties->physicalDimensions.height = connector->mmHeight;
193 		if(pProperties->physicalDimensions.width <= 0 || pProperties->physicalDimensions.height <= 0)
194 		{
195 			pProperties->physicalDimensions.width = connector->modes[0].hdisplay * 25.4 / 96;
196 			pProperties->physicalDimensions.height = connector->modes[0].vdisplay * 25.4 / 96;
197 		}
198 		pProperties->physicalResolution.width = connector->modes[0].hdisplay;
199 		pProperties->physicalResolution.height = connector->modes[0].vdisplay;
200 		pProperties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
201 		pProperties->planeReorderPossible = VK_FALSE;
202 		pProperties->persistentContent = VK_FALSE;
203 		drmModeFreeConnector(connector);
204 		drmModeFreeResources(res);
205 		close(fd);
206 	}
207 
208 	return VK_SUCCESS;
209 }
210 
DisplaySurfaceKHR(const VkDisplaySurfaceCreateInfoKHR * pCreateInfo,void * mem)211 DisplaySurfaceKHR::DisplaySurfaceKHR(const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, void *mem)
212 {
213 	fd = openCard();
214 	if(fd < 0)
215 	{
216 		return;
217 	}
218 
219 	drmModeRes *res = drmModeGetResources(fd);
220 	connector_id = res->connectors[0];
221 	drmModeFreeResources(res);
222 	drmModeConnector *connector = drmModeGetConnector(fd, connector_id);
223 	encoder_id = connector->encoder_id;
224 	memcpy(&mode_info, &connector->modes[0], sizeof(drmModeModeInfo));
225 	drmModeFreeConnector(connector);
226 	drmModeEncoder *encoder = drmModeGetEncoder(fd, encoder_id);
227 	crtc_id = encoder->crtc_id;
228 	drmModeFreeEncoder(encoder);
229 
230 	crtc = drmModeGetCrtc(fd, crtc_id);
231 
232 	struct drm_mode_create_dumb creq;
233 	memset(&creq, 0, sizeof(struct drm_mode_create_dumb));
234 	creq.width = mode_info.hdisplay;
235 	creq.height = mode_info.vdisplay;
236 	creq.bpp = 32;
237 	drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
238 
239 	handle = creq.handle;
240 	width = creq.width;
241 	height = creq.height;
242 	pitch = creq.pitch;
243 	size = creq.size;
244 
245 	drmModeAddFB(fd, width, height, 24, 32, pitch, handle, &fb_id);
246 
247 	struct drm_mode_map_dumb mreq;
248 	memset(&mreq, 0, sizeof(struct drm_mode_map_dumb));
249 	mreq.handle = handle;
250 	drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
251 
252 	fb_buffer = static_cast<uint8_t *>(mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, mreq.offset));
253 }
254 
destroySurface(const VkAllocationCallbacks * pAllocator)255 void DisplaySurfaceKHR::destroySurface(const VkAllocationCallbacks *pAllocator)
256 {
257 	munmap(fb_buffer, size);
258 
259 	drmModeRmFB(fd, fb_id);
260 
261 	struct drm_mode_destroy_dumb dreq;
262 	memset(&dreq, 0, sizeof(struct drm_mode_destroy_dumb));
263 	dreq.handle = handle;
264 	drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
265 
266 	drmModeSetCrtc(fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &connector_id, 1, &crtc->mode);
267 	drmModeFreeCrtc(crtc);
268 
269 	close(fd);
270 }
271 
ComputeRequiredAllocationSize(const VkDisplaySurfaceCreateInfoKHR * pCreateInfo)272 size_t DisplaySurfaceKHR::ComputeRequiredAllocationSize(const VkDisplaySurfaceCreateInfoKHR *pCreateInfo)
273 {
274 	return 0;
275 }
276 
getSurfaceCapabilities(const void * pSurfaceInfoPNext,VkSurfaceCapabilitiesKHR * pSurfaceCapabilities,void * pSurfaceCapabilitiesPNext) const277 VkResult DisplaySurfaceKHR::getSurfaceCapabilities(const void *pSurfaceInfoPNext, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities, void *pSurfaceCapabilitiesPNext) const
278 {
279 	VkExtent2D extent = { width, height };
280 
281 	pSurfaceCapabilities->currentExtent = extent;
282 	pSurfaceCapabilities->minImageExtent = extent;
283 	pSurfaceCapabilities->maxImageExtent = extent;
284 
285 	setCommonSurfaceCapabilities(pSurfaceInfoPNext, pSurfaceCapabilities, pSurfaceCapabilitiesPNext);
286 	return VK_SUCCESS;
287 }
288 
attachImage(PresentImage * image)289 void DisplaySurfaceKHR::attachImage(PresentImage *image)
290 {
291 }
292 
detachImage(PresentImage * image)293 void DisplaySurfaceKHR::detachImage(PresentImage *image)
294 {
295 }
296 
present(PresentImage * image)297 VkResult DisplaySurfaceKHR::present(PresentImage *image)
298 {
299 	image->getImage()->copyTo(fb_buffer, pitch);
300 	drmModeSetCrtc(fd, crtc_id, fb_id, 0, 0, &connector_id, 1, &mode_info);
301 
302 	return VK_SUCCESS;
303 }
304 
305 }  // namespace vk
306