1*4882a593SmuzhiyunFrom 08d6a8d2e5e16d4a15cb58871c591adec0691ee8 Mon Sep 17 00:00:00 2001
2*4882a593SmuzhiyunFrom: Jeffy Chen <jeffy.chen@rock-chips.com>
3*4882a593SmuzhiyunDate: Mon, 23 May 2022 10:57:27 +0800
4*4882a593SmuzhiyunSubject: [PATCH 2/3] kms: Drop dependency on vkCreateDmaBufImageINTEL
5*4882a593Smuzhiyun
6*4882a593SmuzhiyunBased on chromium's gpu/vulkan/vulkan_image{_linux,}.cc
7*4882a593Smuzhiyun
8*4882a593SmuzhiyunSigned-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
9*4882a593Smuzhiyun---
10*4882a593Smuzhiyun meson.build                  |   7 +-
11*4882a593Smuzhiyun src/ws/kms_window_system.cpp | 172 ++++++++++++++++++++++++++---------
12*4882a593Smuzhiyun src/ws/kms_window_system.h   |   1 -
13*4882a593Smuzhiyun 3 files changed, 130 insertions(+), 50 deletions(-)
14*4882a593Smuzhiyun
15*4882a593Smuzhiyundiff --git a/meson.build b/meson.build
16*4882a593Smuzhiyunindex 7d305dc..0d83918 100644
17*4882a593Smuzhiyun--- a/meson.build
18*4882a593Smuzhiyun+++ b/meson.build
19*4882a593Smuzhiyun@@ -32,16 +32,11 @@ wayland_protocols_dep = dependency('wayland-protocols', version : '>= 1.12',
20*4882a593Smuzhiyun wayland_scanner_dep = dependency('wayland-scanner', required : get_option('wayland') == 'true')
21*4882a593Smuzhiyun libdrm_dep = dependency('libdrm', required : get_option('kms') == 'true')
22*4882a593Smuzhiyun gbm_dep = dependency('gbm', required : get_option('kms') == 'true')
23*4882a593Smuzhiyun-has_vulkan_intel_header = cpp.has_header('vulkan/vulkan_intel.h', dependencies: vulkan_dep)
24*4882a593Smuzhiyun-
25*4882a593Smuzhiyun-if get_option('kms') == 'true' and not has_vulkan_intel_header
26*4882a593Smuzhiyun-    error('KMS plugin needs the vulkan_intel.h header, but it couldn\'t be found')
27*4882a593Smuzhiyun-endif
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun build_xcb_ws = xcb_dep.found() and xcb_icccm_dep.found() and get_option('xcb') != 'false'
30*4882a593Smuzhiyun build_wayland_ws = (wayland_client_dep.found() and wayland_protocols_dep.found() and
31*4882a593Smuzhiyun                     wayland_scanner_dep.found() and get_option('wayland') != 'false')
32*4882a593Smuzhiyun-build_kms_ws = libdrm_dep.found() and gbm_dep.found() and has_vulkan_intel_header and get_option('kms') != 'false'
33*4882a593Smuzhiyun+build_kms_ws = libdrm_dep.found() and gbm_dep.found() and get_option('kms') != 'false'
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun if not build_xcb_ws and not build_wayland_ws and not build_kms_ws
36*4882a593Smuzhiyun     error('vkmark needs at least one winsys to work - xcb, wayland or kms')
37*4882a593Smuzhiyundiff --git a/src/ws/kms_window_system.cpp b/src/ws/kms_window_system.cpp
38*4882a593Smuzhiyunindex ca8220f..66618f6 100644
39*4882a593Smuzhiyun--- a/src/ws/kms_window_system.cpp
40*4882a593Smuzhiyun+++ b/src/ws/kms_window_system.cpp
41*4882a593Smuzhiyun@@ -29,7 +29,6 @@
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #include <xf86drm.h>
44*4882a593Smuzhiyun #include <drm_fourcc.h>
45*4882a593Smuzhiyun-#include <vulkan/vulkan_intel.h>
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #include <system_error>
48*4882a593Smuzhiyun #include <fcntl.h>
49*4882a593Smuzhiyun@@ -352,7 +351,6 @@ void KMSWindowSystem::init_vulkan(VulkanState& vulkan_)
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun     vk_image_format = vk::Format::eB8G8R8A8Srgb;
52*4882a593Smuzhiyun     create_gbm_bos();
53*4882a593Smuzhiyun-    create_drm_fbs();
54*4882a593Smuzhiyun     create_vk_images();
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun@@ -428,68 +426,122 @@ void KMSWindowSystem::create_gbm_bos()
58*4882a593Smuzhiyun     }
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun-void KMSWindowSystem::create_drm_fbs()
62*4882a593Smuzhiyun-{
63*4882a593Smuzhiyun-    for (auto const& gbm_bo : gbm_bos)
64*4882a593Smuzhiyun-    {
65*4882a593Smuzhiyun-        uint32_t fb = 0;
66*4882a593Smuzhiyun-
67*4882a593Smuzhiyun-        uint32_t handles[4] = {gbm_bo_get_handle(gbm_bo).u32, 0, 0, 0};
68*4882a593Smuzhiyun-        uint32_t strides[4] = {gbm_bo_get_stride(gbm_bo), 0, 0, 0};
69*4882a593Smuzhiyun-        uint32_t offsets[4] = {0, 0, 0, 0};
70*4882a593Smuzhiyun-
71*4882a593Smuzhiyun-        auto const ret = drmModeAddFB2(
72*4882a593Smuzhiyun-            drm_fd, vk_extent.width, vk_extent.height,
73*4882a593Smuzhiyun-            DRM_FORMAT_XRGB8888,
74*4882a593Smuzhiyun-            handles, strides, offsets, &fb, 0);
75*4882a593Smuzhiyun-
76*4882a593Smuzhiyun-        if (ret < 0)
77*4882a593Smuzhiyun-            throw std::system_error{-ret, std::system_category(), "Failed to add drm fb"};
78*4882a593Smuzhiyun+// TODO: Use an official extension to create the VkImages when it becomes
79*4882a593Smuzhiyun+// available (e.g. VK_MESAX_external_image_dma_buf)
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun-        drm_fbs.push_back(
82*4882a593Smuzhiyun-            ManagedResource<uint32_t>{
83*4882a593Smuzhiyun-                std::move(fb),
84*4882a593Smuzhiyun-                [this] (auto& fb) { drmModeRmFB(drm_fd, fb); }});
85*4882a593Smuzhiyun+static int find_memory_type_index(VkPhysicalDevice physical_device,
86*4882a593Smuzhiyun+                                  const VkMemoryRequirements* requirements,
87*4882a593Smuzhiyun+                                  VkMemoryPropertyFlags flags) {
88*4882a593Smuzhiyun+    VkPhysicalDeviceMemoryProperties properties;
89*4882a593Smuzhiyun+    vkGetPhysicalDeviceMemoryProperties(physical_device, &properties);
90*4882a593Smuzhiyun+    for (int i = 0; i <= 31; i++) {
91*4882a593Smuzhiyun+        if (((1u << i) & requirements->memoryTypeBits) == 0)
92*4882a593Smuzhiyun+            continue;
93*4882a593Smuzhiyun+        if ((properties.memoryTypes[i].propertyFlags & flags) != flags)
94*4882a593Smuzhiyun+            continue;
95*4882a593Smuzhiyun+        return i;
96*4882a593Smuzhiyun     }
97*4882a593Smuzhiyun+    return -1;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun-// TODO: Use an official extension to create the VkImages when it becomes
101*4882a593Smuzhiyun-// available (e.g. VK_MESAX_external_image_dma_buf)
102*4882a593Smuzhiyun void KMSWindowSystem::create_vk_images()
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun-    auto const create_dma_buf_image =
105*4882a593Smuzhiyun-        reinterpret_cast<PFN_vkCreateDmaBufImageINTEL>(
106*4882a593Smuzhiyun-            vulkan->device().getProcAddr("vkCreateDmaBufImageINTEL"));
107*4882a593Smuzhiyun-
108*4882a593Smuzhiyun-    if (!create_dma_buf_image)
109*4882a593Smuzhiyun-        throw std::runtime_error{"Failed to get vkCreateDmaBufImageINTEL function pointer"};
110*4882a593Smuzhiyun-
111*4882a593Smuzhiyun     for (auto const& gbm_bo : gbm_bos)
112*4882a593Smuzhiyun     {
113*4882a593Smuzhiyun         auto const fd = ManagedResource<int>{gbm_bo_get_fd(gbm_bo), close};
114*4882a593Smuzhiyun-        auto const stride = gbm_bo_get_stride(gbm_bo);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun-        VkDmaBufImageCreateInfo create_info{};
117*4882a593Smuzhiyun-        create_info.sType = static_cast<VkStructureType>(VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL);
118*4882a593Smuzhiyun-        create_info.fd = fd;
119*4882a593Smuzhiyun-        create_info.format = static_cast<VkFormat>(vk_image_format);
120*4882a593Smuzhiyun-        create_info.extent = {vk_extent.width, vk_extent.height, 1};
121*4882a593Smuzhiyun-        create_info.strideInBytes = stride;
122*4882a593Smuzhiyun+        VkExternalMemoryImageCreateInfoKHR external_image_create_info = {
123*4882a593Smuzhiyun+            .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
124*4882a593Smuzhiyun+            .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
125*4882a593Smuzhiyun+        };
126*4882a593Smuzhiyun+
127*4882a593Smuzhiyun+        uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
128*4882a593Smuzhiyun+        VkImageDrmFormatModifierListCreateInfoEXT modifier_info = {
129*4882a593Smuzhiyun+            .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
130*4882a593Smuzhiyun+            .drmFormatModifierCount = 1,
131*4882a593Smuzhiyun+            .pDrmFormatModifiers = &modifier,
132*4882a593Smuzhiyun+        };
133*4882a593Smuzhiyun+		external_image_create_info.pNext = &modifier_info;
134*4882a593Smuzhiyun+
135*4882a593Smuzhiyun+        VkImportMemoryFdInfoKHR import_memory_fd_info = {
136*4882a593Smuzhiyun+            .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
137*4882a593Smuzhiyun+            .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
138*4882a593Smuzhiyun+            .fd = fd,
139*4882a593Smuzhiyun+        };
140*4882a593Smuzhiyun+
141*4882a593Smuzhiyun+        VkImageCreateInfo create_info{};
142*4882a593Smuzhiyun+        create_info = {
143*4882a593Smuzhiyun+            .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
144*4882a593Smuzhiyun+            .pNext = &external_image_create_info,
145*4882a593Smuzhiyun+            .flags = 0,
146*4882a593Smuzhiyun+            .imageType = VK_IMAGE_TYPE_2D,
147*4882a593Smuzhiyun+            .format = static_cast<VkFormat>(vk_image_format),
148*4882a593Smuzhiyun+            .extent = {vk_extent.width, vk_extent.height, 1},
149*4882a593Smuzhiyun+            .mipLevels = 1,
150*4882a593Smuzhiyun+            .arrayLayers = 1,
151*4882a593Smuzhiyun+            .samples = VK_SAMPLE_COUNT_1_BIT,
152*4882a593Smuzhiyun+            .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
153*4882a593Smuzhiyun+            .usage = 0,
154*4882a593Smuzhiyun+            .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
155*4882a593Smuzhiyun+            .queueFamilyIndexCount = 0,
156*4882a593Smuzhiyun+            .pQueueFamilyIndices = nullptr,
157*4882a593Smuzhiyun+            .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
158*4882a593Smuzhiyun+        };
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun         VkImage image;
161*4882a593Smuzhiyun-        VkDeviceMemory device_memory;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun-        VkResult result = create_dma_buf_image(
164*4882a593Smuzhiyun+        VkResult result = vkCreateImage(
165*4882a593Smuzhiyun             vulkan->device(),
166*4882a593Smuzhiyun             &create_info,
167*4882a593Smuzhiyun             nullptr,
168*4882a593Smuzhiyun-            &device_memory,
169*4882a593Smuzhiyun             &image);
170*4882a593Smuzhiyun+        if (result != VK_SUCCESS)
171*4882a593Smuzhiyun+        {
172*4882a593Smuzhiyun+            vk::throwResultException(static_cast<vk::Result>(result),
173*4882a593Smuzhiyun+                                     "vkCreateImage");
174*4882a593Smuzhiyun+        }
175*4882a593Smuzhiyun+
176*4882a593Smuzhiyun+        VkMemoryDedicatedAllocateInfoKHR dedicated_memory_info = {
177*4882a593Smuzhiyun+            .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
178*4882a593Smuzhiyun+            .pNext = &import_memory_fd_info,
179*4882a593Smuzhiyun+            .image = image,
180*4882a593Smuzhiyun+        };
181*4882a593Smuzhiyun+
182*4882a593Smuzhiyun+        VkMemoryRequirements requirements;
183*4882a593Smuzhiyun+        vkGetImageMemoryRequirements(vulkan->device(), image, &requirements);
184*4882a593Smuzhiyun+        if (!requirements.memoryTypeBits) {
185*4882a593Smuzhiyun+            throw std::runtime_error{"Failed in vkGetImageMemoryRequirements"};
186*4882a593Smuzhiyun+        }
187*4882a593Smuzhiyun+
188*4882a593Smuzhiyun+        int index = find_memory_type_index(vulkan->physical_device(),
189*4882a593Smuzhiyun+                                           &requirements,
190*4882a593Smuzhiyun+                                           VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
191*4882a593Smuzhiyun+        if (index < 0) {
192*4882a593Smuzhiyun+            throw std::runtime_error{"Failed to get memoryTypeIndex"};
193*4882a593Smuzhiyun+        }
194*4882a593Smuzhiyun+
195*4882a593Smuzhiyun+        VkMemoryAllocateInfo memory_allocate_info = {
196*4882a593Smuzhiyun+            .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
197*4882a593Smuzhiyun+            .pNext = &dedicated_memory_info,
198*4882a593Smuzhiyun+            .allocationSize = requirements.size,
199*4882a593Smuzhiyun+            .memoryTypeIndex = (uint32_t)index,
200*4882a593Smuzhiyun+        };
201*4882a593Smuzhiyun+
202*4882a593Smuzhiyun+        VkDeviceMemory device_memory = VK_NULL_HANDLE;
203*4882a593Smuzhiyun+        result = vkAllocateMemory(vulkan->device(), &memory_allocate_info,
204*4882a593Smuzhiyun+                                  nullptr /* pAllocator */, &device_memory);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun         if (result != VK_SUCCESS)
207*4882a593Smuzhiyun         {
208*4882a593Smuzhiyun             vk::throwResultException(static_cast<vk::Result>(result),
209*4882a593Smuzhiyun-                                     "vkCreateDmbBufImageINTEL");
210*4882a593Smuzhiyun+                                     "vkAllocateMemory");
211*4882a593Smuzhiyun+        }
212*4882a593Smuzhiyun+
213*4882a593Smuzhiyun+        result = vkBindImageMemory(vulkan->device(), image, device_memory,
214*4882a593Smuzhiyun+                                   0 /* memoryOffset */);
215*4882a593Smuzhiyun+        if (result != VK_SUCCESS) {
216*4882a593Smuzhiyun+            vk::throwResultException(static_cast<vk::Result>(result),
217*4882a593Smuzhiyun+                                     "vkBindImageMemory");
218*4882a593Smuzhiyun         }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun         vk_images.push_back(
221*4882a593Smuzhiyun@@ -500,6 +552,40 @@ void KMSWindowSystem::create_vk_images()
222*4882a593Smuzhiyun                     vptr->device().destroyImage(image);
223*4882a593Smuzhiyun                     vptr->device().freeMemory(device_memory);
224*4882a593Smuzhiyun                 }});
225*4882a593Smuzhiyun+
226*4882a593Smuzhiyun+        std::array<VkSubresourceLayout, 4> layouts = {};
227*4882a593Smuzhiyun+        const VkImageSubresource image_subresource = {
228*4882a593Smuzhiyun+			.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
229*4882a593Smuzhiyun+			.mipLevel = 0,
230*4882a593Smuzhiyun+			.arrayLayer = 0,
231*4882a593Smuzhiyun+		};
232*4882a593Smuzhiyun+		vkGetImageSubresourceLayout(vulkan->device(), image,
233*4882a593Smuzhiyun+									&image_subresource, &layouts[0]);
234*4882a593Smuzhiyun+
235*4882a593Smuzhiyun+        uint32_t fb = 0;
236*4882a593Smuzhiyun+
237*4882a593Smuzhiyun+        uint32_t handles[4] = {0,};
238*4882a593Smuzhiyun+        uint32_t strides[4] = {0,};
239*4882a593Smuzhiyun+        uint32_t offsets[4] = {0,};
240*4882a593Smuzhiyun+
241*4882a593Smuzhiyun+        for (auto i = 0; i < gbm_bo_get_plane_count(gbm_bo); i++) {
242*4882a593Smuzhiyun+            handles[i] = gbm_bo_get_handle(gbm_bo).u32;
243*4882a593Smuzhiyun+            offsets[i] = layouts[i].offset;
244*4882a593Smuzhiyun+            strides[i] = layouts[i].rowPitch;
245*4882a593Smuzhiyun+        }
246*4882a593Smuzhiyun+
247*4882a593Smuzhiyun+        auto const ret = drmModeAddFB2(
248*4882a593Smuzhiyun+            drm_fd, vk_extent.width, vk_extent.height,
249*4882a593Smuzhiyun+            DRM_FORMAT_XRGB8888,
250*4882a593Smuzhiyun+            handles, strides, offsets, &fb, 0);
251*4882a593Smuzhiyun+
252*4882a593Smuzhiyun+        if (ret < 0)
253*4882a593Smuzhiyun+            throw std::system_error{-ret, std::system_category(), "Failed to add drm fb"};
254*4882a593Smuzhiyun+
255*4882a593Smuzhiyun+        drm_fbs.push_back(
256*4882a593Smuzhiyun+            ManagedResource<uint32_t>{
257*4882a593Smuzhiyun+            std::move(fb),
258*4882a593Smuzhiyun+            [this] (auto& fb) { drmModeRmFB(drm_fd, fb); }});
259*4882a593Smuzhiyun     }
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyundiff --git a/src/ws/kms_window_system.h b/src/ws/kms_window_system.h
263*4882a593Smuzhiyunindex 4389ef7..ca304c0 100644
264*4882a593Smuzhiyun--- a/src/ws/kms_window_system.h
265*4882a593Smuzhiyun+++ b/src/ws/kms_window_system.h
266*4882a593Smuzhiyun@@ -68,7 +68,6 @@ public:
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun protected:
269*4882a593Smuzhiyun     void create_gbm_bos();
270*4882a593Smuzhiyun-    void create_drm_fbs();
271*4882a593Smuzhiyun     void create_vk_images();
272*4882a593Smuzhiyun     void wait_for_drm_page_flip_event();
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun--
275*4882a593Smuzhiyun2.20.1
276*4882a593Smuzhiyun
277