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