| // Copyright 2020 The SwiftShader Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "DisplaySurfaceKHR.hpp" |
| |
| #include "Vulkan/VkDeviceMemory.hpp" |
| #include "Vulkan/VkImage.hpp" |
| |
| #include <dirent.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <sys/mman.h> |
| #include <unistd.h> |
| #include <xf86drm.h> |
| |
| namespace vk { |
| |
| static int openCard() |
| { |
| constexpr size_t DIR_NAME_MAX = sizeof("/dev/dri/") - 1; |
| constexpr size_t PRE_NODE_NAME_MAX = sizeof("card") - 1; |
| constexpr size_t POST_NODE_NAME_MAX = sizeof("255") - 1; |
| constexpr size_t NODE_NAME_MAX = |
| DIR_NAME_MAX + PRE_NODE_NAME_MAX + POST_NODE_NAME_MAX; |
| char name[NODE_NAME_MAX] = "/dev/dri/"; |
| int fd = -VK_NOT_READY; |
| |
| /* |
| * Open the first DRM/KMS device. The libdrm drmOpen*() functions |
| * from drmOpen() is of no practical use as any modern system will |
| * handle that through udev or an equivalent component. |
| */ |
| DIR *folder = opendir(name); |
| if(!folder) |
| { |
| return -errno; |
| } |
| |
| strncat(name, "card", 5); |
| for(struct dirent *res; (res = readdir(folder));) |
| { |
| if(!strncmp(res->d_name, "card", 4)) |
| { |
| strncat(name, res->d_name + PRE_NODE_NAME_MAX, 4); |
| fd = open(name, O_RDWR); |
| if(fd >= 0) |
| { |
| break; |
| } |
| |
| name[DIR_NAME_MAX + PRE_NODE_NAME_MAX] = 0; |
| fd = -errno; |
| } |
| } |
| |
| closedir(folder); |
| |
| return fd; |
| } |
| |
| VkResult DisplaySurfaceKHR::GetDisplayModeProperties(uint32_t *pPropertyCount, VkDisplayModePropertiesKHR *pProperties) |
| { |
| *pPropertyCount = 1; |
| |
| if(pProperties) |
| { |
| const int fd = openCard(); |
| if(fd < 0) |
| { |
| return VK_NOT_READY; |
| } |
| |
| drmModeRes *res = drmModeGetResources(fd); |
| drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[0]); |
| pProperties->displayMode = (uintptr_t)connector->modes[0].name; |
| pProperties->parameters.visibleRegion.width = connector->modes[0].hdisplay; |
| pProperties->parameters.visibleRegion.height = connector->modes[0].vdisplay; |
| pProperties->parameters.refreshRate = connector->modes[0].vrefresh * 1000; |
| drmModeFreeConnector(connector); |
| drmModeFreeResources(res); |
| close(fd); |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult DisplaySurfaceKHR::GetDisplayPlaneCapabilities(VkDisplayPlaneCapabilitiesKHR *pCapabilities) |
| { |
| const int fd = openCard(); |
| if(fd < 0) |
| { |
| return VK_NOT_READY; |
| } |
| |
| drmModeRes *res = drmModeGetResources(fd); |
| drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[0]); |
| pCapabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; |
| pCapabilities->minSrcPosition.x = 0; |
| pCapabilities->minSrcPosition.y = 0; |
| pCapabilities->maxSrcPosition.x = 0; |
| pCapabilities->maxSrcPosition.y = 0; |
| pCapabilities->minSrcExtent.width = connector->modes[0].hdisplay; |
| pCapabilities->minSrcExtent.height = connector->modes[0].vdisplay; |
| pCapabilities->maxSrcExtent.width = connector->modes[0].hdisplay; |
| pCapabilities->maxSrcExtent.height = connector->modes[0].vdisplay; |
| pCapabilities->minDstPosition.x = 0; |
| pCapabilities->minDstPosition.y = 0; |
| pCapabilities->maxDstPosition.x = 0; |
| pCapabilities->maxDstPosition.y = 0; |
| pCapabilities->minDstExtent.width = connector->modes[0].hdisplay; |
| pCapabilities->minDstExtent.height = connector->modes[0].vdisplay; |
| pCapabilities->maxDstExtent.width = connector->modes[0].hdisplay; |
| pCapabilities->maxDstExtent.height = connector->modes[0].vdisplay; |
| drmModeFreeConnector(connector); |
| drmModeFreeResources(res); |
| close(fd); |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult DisplaySurfaceKHR::GetDisplayPlaneSupportedDisplays(uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) |
| { |
| *pDisplayCount = 1; |
| |
| if(pDisplays) |
| { |
| const int fd = openCard(); |
| if(fd < 0) |
| { |
| return VK_NOT_READY; |
| } |
| |
| drmModeRes *res = drmModeGetResources(fd); |
| *pDisplays = res->connectors[0]; |
| drmModeFreeResources(res); |
| close(fd); |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult DisplaySurfaceKHR::GetPhysicalDeviceDisplayPlaneProperties(uint32_t *pPropertyCount, VkDisplayPlanePropertiesKHR *pProperties) |
| { |
| *pPropertyCount = 1; |
| |
| if(pProperties) |
| { |
| const int fd = openCard(); |
| if(fd < 0) |
| { |
| return VK_NOT_READY; |
| } |
| |
| drmModeRes *res = drmModeGetResources(fd); |
| pProperties->currentDisplay = res->connectors[0]; |
| pProperties->currentStackIndex = 0; |
| drmModeFreeResources(res); |
| close(fd); |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| VkResult DisplaySurfaceKHR::GetPhysicalDeviceDisplayProperties(uint32_t *pPropertyCount, VkDisplayPropertiesKHR *pProperties) |
| { |
| *pPropertyCount = 1; |
| |
| if(pProperties) |
| { |
| const int fd = openCard(); |
| if(fd < 0) |
| { |
| return VK_NOT_READY; |
| } |
| |
| drmModeRes *res = drmModeGetResources(fd); |
| drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[0]); |
| pProperties->display = res->connectors[0]; |
| pProperties->displayName = "monitor"; |
| pProperties->physicalDimensions.width = connector->mmWidth; |
| pProperties->physicalDimensions.height = connector->mmHeight; |
| if(pProperties->physicalDimensions.width <= 0 || pProperties->physicalDimensions.height <= 0) |
| { |
| pProperties->physicalDimensions.width = connector->modes[0].hdisplay * 25.4 / 96; |
| pProperties->physicalDimensions.height = connector->modes[0].vdisplay * 25.4 / 96; |
| } |
| pProperties->physicalResolution.width = connector->modes[0].hdisplay; |
| pProperties->physicalResolution.height = connector->modes[0].vdisplay; |
| pProperties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; |
| pProperties->planeReorderPossible = VK_FALSE; |
| pProperties->persistentContent = VK_FALSE; |
| drmModeFreeConnector(connector); |
| drmModeFreeResources(res); |
| close(fd); |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| DisplaySurfaceKHR::DisplaySurfaceKHR(const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, void *mem) |
| { |
| fd = openCard(); |
| if(fd < 0) |
| { |
| return; |
| } |
| |
| drmModeRes *res = drmModeGetResources(fd); |
| connector_id = res->connectors[0]; |
| drmModeFreeResources(res); |
| drmModeConnector *connector = drmModeGetConnector(fd, connector_id); |
| encoder_id = connector->encoder_id; |
| memcpy(&mode_info, &connector->modes[0], sizeof(drmModeModeInfo)); |
| drmModeFreeConnector(connector); |
| drmModeEncoder *encoder = drmModeGetEncoder(fd, encoder_id); |
| crtc_id = encoder->crtc_id; |
| drmModeFreeEncoder(encoder); |
| |
| crtc = drmModeGetCrtc(fd, crtc_id); |
| |
| struct drm_mode_create_dumb creq; |
| memset(&creq, 0, sizeof(struct drm_mode_create_dumb)); |
| creq.width = mode_info.hdisplay; |
| creq.height = mode_info.vdisplay; |
| creq.bpp = 32; |
| drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); |
| |
| handle = creq.handle; |
| width = creq.width; |
| height = creq.height; |
| pitch = creq.pitch; |
| size = creq.size; |
| |
| drmModeAddFB(fd, width, height, 24, 32, pitch, handle, &fb_id); |
| |
| struct drm_mode_map_dumb mreq; |
| memset(&mreq, 0, sizeof(struct drm_mode_map_dumb)); |
| mreq.handle = handle; |
| drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); |
| |
| fb_buffer = static_cast<uint8_t *>(mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, mreq.offset)); |
| } |
| |
| void DisplaySurfaceKHR::destroySurface(const VkAllocationCallbacks *pAllocator) |
| { |
| munmap(fb_buffer, size); |
| |
| drmModeRmFB(fd, fb_id); |
| |
| struct drm_mode_destroy_dumb dreq; |
| memset(&dreq, 0, sizeof(struct drm_mode_destroy_dumb)); |
| dreq.handle = handle; |
| drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); |
| |
| drmModeSetCrtc(fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &connector_id, 1, &crtc->mode); |
| drmModeFreeCrtc(crtc); |
| |
| close(fd); |
| } |
| |
| size_t DisplaySurfaceKHR::ComputeRequiredAllocationSize(const VkDisplaySurfaceCreateInfoKHR *pCreateInfo) |
| { |
| return 0; |
| } |
| |
| VkResult DisplaySurfaceKHR::getSurfaceCapabilities(const void *pSurfaceInfoPNext, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities, void *pSurfaceCapabilitiesPNext) const |
| { |
| setCommonSurfaceCapabilities(pSurfaceInfoPNext, pSurfaceCapabilities, pSurfaceCapabilitiesPNext); |
| |
| VkExtent2D extent = { width, height }; |
| |
| pSurfaceCapabilities->currentExtent = extent; |
| pSurfaceCapabilities->minImageExtent = extent; |
| pSurfaceCapabilities->maxImageExtent = extent; |
| return VK_SUCCESS; |
| } |
| |
| void DisplaySurfaceKHR::attachImage(PresentImage *image) |
| { |
| } |
| |
| void DisplaySurfaceKHR::detachImage(PresentImage *image) |
| { |
| } |
| |
| VkResult DisplaySurfaceKHR::present(PresentImage *image) |
| { |
| image->getImage()->copyTo(fb_buffer, pitch); |
| drmModeSetCrtc(fd, crtc_id, fb_id, 0, 0, &connector_id, 1, &mode_info); |
| |
| return VK_SUCCESS; |
| } |
| |
| } // namespace vk |