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