b237cfb55d693900d4c944ac72cc1cd5fcf25010
[platform/upstream/gstreamer.git] / sys / applemedia / iosurfacevulkanmemory.c
1 /*
2  * GStreamer
3  * Copyright (C) 2019 Matthew Waters <matthew@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "iosurfacevulkanmemory.h"
26 #include "metal-helpers.h"
27
28 GST_DEBUG_CATEGORY_STATIC (GST_CAT_IO_SURFACE_VULKAN_MEMORY);
29 #define GST_CAT_DEFAULT GST_CAT_IO_SURFACE_VULKAN_MEMORY
30
31 G_DEFINE_TYPE (GstIOSurfaceVulkanMemoryAllocator,
32     gst_io_surface_vulkan_memory_allocator,
33     GST_TYPE_VULKAN_IMAGE_MEMORY_ALLOCATOR);
34
35 typedef struct
36 {
37   GstIOSurfaceVulkanMemory *memory;
38   IOSurfaceRef surface;
39 } ContextThreadData;
40
41 static GstAllocator *_io_surface_vulkan_memory_allocator;
42
43 static void
44 _mem_free (GstAllocator * allocator, GstMemory * mem)
45 {
46   gst_io_surface_vulkan_memory_set_surface ((GstIOSurfaceVulkanMemory *) mem,
47       NULL);
48
49   GST_ALLOCATOR_CLASS
50       (gst_io_surface_vulkan_memory_allocator_parent_class)->free (allocator,
51       mem);
52 }
53
54 static gpointer
55 _io_surface_vulkan_memory_allocator_map (GstMemory * bmem,
56     GstMapInfo * info, gsize size)
57 {
58   GstIOSurfaceVulkanMemory *mem = (GstIOSurfaceVulkanMemory *) bmem;
59
60   GST_LOG ("mapping surface %p flags %d", mem->surface, info->flags);
61
62   if (!(info->flags & GST_MAP_WRITE)) {
63     IOSurfaceLock (mem->surface, kIOSurfaceLockReadOnly, NULL);
64     return IOSurfaceGetBaseAddressOfPlane (mem->surface, mem->plane);
65   } else {
66     GST_ERROR ("couldn't map IOSurface %p flags %d", mem->surface, info->flags);
67     return NULL;
68   }
69 }
70
71 static void
72 _io_surface_vulkan_memory_allocator_unmap (GstMemory * bmem, GstMapInfo * info)
73 {
74   GstIOSurfaceVulkanMemory *mem = (GstIOSurfaceVulkanMemory *) bmem;
75
76   GST_LOG ("unmapping surface %p flags %d", mem->surface, info->flags);
77
78   IOSurfaceUnlock (mem->surface, kIOSurfaceLockReadOnly, NULL);
79 }
80
81 static GstMemory *
82 _mem_alloc (GstAllocator * allocator, gsize size, GstAllocationParams * params)
83 {
84   g_warning
85       ("use gst_io_surface_vulkan_memory_wrapped () to allocate from this "
86       "IOSurface allocator");
87
88   return NULL;
89 }
90
91 static void
92     gst_io_surface_vulkan_memory_allocator_class_init
93     (GstIOSurfaceVulkanMemoryAllocatorClass * klass)
94 {
95   GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
96
97   allocator_class->alloc = _mem_alloc;
98   allocator_class->free = _mem_free;
99 }
100
101 static void
102 gst_io_surface_vulkan_memory_allocator_init (GstIOSurfaceVulkanMemoryAllocator *
103     allocator)
104 {
105   GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
106
107   alloc->mem_type = GST_IO_SURFACE_VULKAN_MEMORY_ALLOCATOR_NAME;
108   GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
109
110   alloc->mem_map_full = _io_surface_vulkan_memory_allocator_map;
111   alloc->mem_unmap_full = _io_surface_vulkan_memory_allocator_unmap;
112 }
113
114 void
115 gst_io_surface_vulkan_memory_init (void)
116 {
117   static volatile gsize _init = 0;
118
119   if (g_once_init_enter (&_init)) {
120     GST_DEBUG_CATEGORY_INIT (GST_CAT_IO_SURFACE_VULKAN_MEMORY,
121         "iosurfacevulkan", 0, "IOSurface Vulkan Buffer");
122
123     _io_surface_vulkan_memory_allocator =
124         g_object_new (GST_TYPE_IO_SURFACE_VULKAN_MEMORY_ALLOCATOR, NULL);
125     gst_object_ref_sink (_io_surface_vulkan_memory_allocator);
126
127     gst_allocator_register (GST_IO_SURFACE_VULKAN_MEMORY_ALLOCATOR_NAME,
128         gst_object_ref (_io_surface_vulkan_memory_allocator));
129     g_once_init_leave (&_init, 1);
130   }
131 }
132
133 gboolean
134 gst_is_io_surface_vulkan_memory (GstMemory * mem)
135 {
136   return mem != NULL && mem->allocator != NULL &&
137       g_type_is_a (G_OBJECT_TYPE (mem->allocator),
138       GST_TYPE_IO_SURFACE_VULKAN_MEMORY_ALLOCATOR);
139 }
140
141 static GstIOSurfaceVulkanMemory *
142 _io_surface_vulkan_memory_new (GstVulkanDevice * device, IOSurfaceRef surface,
143     unsigned int /* MTLPixelFormat */ fmt, GstVideoInfo * info, guint plane,
144     gpointer user_data, GDestroyNotify notify)
145 {
146   GstIOSurfaceVulkanMemory *mem;
147   GstAllocationParams params = { 0, };
148   VkImageCreateInfo image_info;
149   VkPhysicalDevice gpu;
150   VkImageUsageFlags usage;
151   VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
152   VkFormat vk_format;
153   VkImage image;
154   GError *error = NULL;
155   VkResult err;
156
157   mem = g_new0 (GstIOSurfaceVulkanMemory, 1);
158
159   vk_format = metal_format_to_vulkan (fmt);
160   /* FIXME: choose from outside */
161   usage =
162       VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
163       VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
164
165   /* *INDENT-OFF* */
166   image_info = (VkImageCreateInfo) {
167       .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
168       .pNext = NULL,
169       .flags = 0,
170       .imageType = VK_IMAGE_TYPE_2D,
171       .format = vk_format,
172       /* MoltenVK double checks these against the IOSurface in vkUseIOSurface()
173        * and will fail if they do not match */
174       .extent = (VkExtent3D) { GST_VIDEO_INFO_COMP_WIDTH (info, plane), GST_VIDEO_INFO_COMP_HEIGHT (info, plane), 1 },
175       .mipLevels = 1,
176       .arrayLayers = 1,
177       .samples = VK_SAMPLE_COUNT_1_BIT,
178       .tiling = tiling,
179       .usage = usage,
180       .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
181       .queueFamilyIndexCount = 0,
182       .pQueueFamilyIndices = NULL,
183       .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
184   };
185   /* *INDENT-ON* */
186
187   gpu = gst_vulkan_device_get_physical_device (device);
188
189   err = vkCreateImage (device->device, &image_info, NULL, &image);
190   if (gst_vulkan_error_to_g_error (err, &error, "vkCreateImage") < 0)
191     goto vk_error;
192
193   vkGetImageMemoryRequirements (device->device, image,
194       &mem->vulkan_mem.requirements);
195
196   gst_vulkan_image_memory_init (&mem->vulkan_mem,
197       _io_surface_vulkan_memory_allocator, NULL, device, usage, &params,
198       mem->vulkan_mem.requirements.size, user_data, notify);
199   mem->vulkan_mem.create_info = image_info;
200   mem->vulkan_mem.image = image;
201   mem->vulkan_mem.barrier.image_layout = VK_IMAGE_LAYOUT_GENERAL;
202
203   err =
204       vkGetPhysicalDeviceImageFormatProperties (gpu, vk_format,
205       VK_IMAGE_TYPE_2D, tiling, usage, 0, &mem->vulkan_mem.format_properties);
206   if (gst_vulkan_error_to_g_error (err, &error,
207           "vkGetPhysicalDeviceImageFormatProperties") < 0)
208     goto vk_error;
209
210   GST_MINI_OBJECT_FLAG_SET (mem, GST_MEMORY_FLAG_READONLY);
211
212   mem->surface = NULL;
213   mem->plane = plane;
214   gst_io_surface_vulkan_memory_set_surface (mem, surface);
215
216   return mem;
217
218 vk_error:
219   {
220     GST_CAT_ERROR (GST_CAT_IO_SURFACE_VULKAN_MEMORY,
221         "Failed to allocate image memory %s", error->message);
222     g_clear_error (&error);
223     goto error;
224   }
225
226 error:
227   {
228     if (mem)
229       gst_memory_unref ((GstMemory *) mem);
230     return NULL;
231   }
232 }
233
234 GstIOSurfaceVulkanMemory *
235 gst_io_surface_vulkan_memory_wrapped (GstVulkanDevice * device,
236     IOSurfaceRef surface, unsigned int /* MTLPixelFormat */ fmt,
237     GstVideoInfo * info, guint plane, gpointer user_data, GDestroyNotify notify)
238 {
239   return _io_surface_vulkan_memory_new (device, surface, fmt, info, plane,
240       user_data, notify);
241 }