1/*
2 * Copyright (C) 2018 Igalia S.L
3 * Copyright (C) 2018 Metrological Group B.V.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include "config.h"
21#include "GstAllocatorFastMalloc.h"
22
23#include <gst/gst.h>
24#include <wtf/FastMalloc.h>
25
26typedef struct {
27 GstMemory base;
28
29 uint8_t* data;
30} GstMemoryFastMalloc;
31
32typedef struct {
33 GstAllocator parent;
34} GstAllocatorFastMalloc;
35
36typedef struct {
37 GstAllocatorClass parent;
38} GstAllocatorFastMallocClass;
39
40G_DEFINE_TYPE(GstAllocatorFastMalloc, gst_allocator_fast_malloc, GST_TYPE_ALLOCATOR)
41
42static GstMemoryFastMalloc* gstMemoryFastMallocNew(GstAllocator* allocator, gsize size, gsize alignment, gsize offset, gsize padding, GstMemoryFlags flags)
43{
44 // alignment should be a (power-of-two - 1).
45 alignment |= gst_memory_alignment;
46 ASSERT(!((alignment + 1) & alignment));
47
48 gsize headerSize = (sizeof(GstMemoryFastMalloc) + alignment) & ~alignment;
49 gsize allocationSize = offset + size + padding;
50 auto* memory = static_cast<GstMemoryFastMalloc*>(tryFastAlignedMalloc(alignment + 1, headerSize + allocationSize));
51 if (!memory)
52 return nullptr;
53
54 memory->data = reinterpret_cast<uint8_t*>(memory) + headerSize;
55
56 if (offset && (flags & GST_MEMORY_FLAG_ZERO_PREFIXED))
57 std::memset(memory->data, 0, offset);
58 if (padding && (flags & GST_MEMORY_FLAG_ZERO_PADDED))
59 std::memset(memory->data + offset + size, 0, padding);
60
61 gst_memory_init(GST_MEMORY_CAST(memory), flags, allocator, nullptr, allocationSize, alignment, offset, size);
62
63 return memory;
64}
65
66static GstMemory* gstAllocatorFastMallocAlloc(GstAllocator* allocator, gsize size, GstAllocationParams* params)
67{
68 ASSERT(G_TYPE_CHECK_INSTANCE_TYPE(allocator, gst_allocator_fast_malloc_get_type()));
69
70 return GST_MEMORY_CAST(gstMemoryFastMallocNew(allocator, size, params->align, params->prefix, params->padding, params->flags));
71}
72
73static void gstAllocatorFastMallocFree(GstAllocator* allocator, GstMemory* memory)
74{
75#if !ASSERT_DISABLED
76 ASSERT(G_TYPE_CHECK_INSTANCE_TYPE(allocator, gst_allocator_fast_malloc_get_type()));
77#else
78 UNUSED_PARAM(allocator);
79#endif
80
81 fastAlignedFree(memory);
82}
83
84static gpointer gstAllocatorFastMallocMemMap(GstMemoryFastMalloc* memory, gsize, GstMapFlags)
85{
86 return memory->data;
87}
88
89static void gstAllocatorFastMallocMemUnmap(GstMemoryFastMalloc*)
90{
91}
92
93static GstMemoryFastMalloc* gstAllocatorFastMallocMemCopy(GstMemoryFastMalloc* memory, gssize offset, gsize size)
94{
95 if (size == static_cast<gsize>(-1))
96 size = memory->base.size > static_cast<gsize>(offset) ? memory->base.size - offset : 0;
97
98 auto* copy = gstMemoryFastMallocNew(memory->base.allocator, size, memory->base.align, 0, 0, static_cast<GstMemoryFlags>(0));
99 if (!copy)
100 return nullptr;
101
102 std::memcpy(copy->data, memory->data + memory->base.offset + offset, size);
103 return copy;
104}
105
106static GstMemoryFastMalloc* gstAllocatorFastMallocMemShare(GstMemoryFastMalloc* memory, gssize offset, gsize size)
107{
108 GstMemoryFastMalloc* sharedMemory;
109 if (!tryFastMalloc(sizeof(GstMemoryFastMalloc)).getValue(sharedMemory))
110 return nullptr;
111
112 sharedMemory->data = memory->data;
113
114 if (size == static_cast<gsize>(-1))
115 size = memory->base.size - offset;
116
117 auto* parent = memory->base.parent ? memory->base.parent : GST_MEMORY_CAST(memory);
118 gst_memory_init(GST_MEMORY_CAST(sharedMemory),
119 static_cast<GstMemoryFlags>(GST_MINI_OBJECT_FLAGS(parent) | GST_MINI_OBJECT_FLAG_LOCK_READONLY),
120 memory->base.allocator, parent, memory->base.maxsize, memory->base.align,
121 memory->base.offset + offset, size);
122
123 return sharedMemory;
124}
125
126static gboolean gstAllocatorFastMallocMemIsSpan(GstMemoryFastMalloc* memory, GstMemoryFastMalloc* other, gsize* offset)
127{
128 if (offset) {
129 auto* parent = reinterpret_cast<GstMemoryFastMalloc*>(memory->base.parent);
130 ASSERT(parent);
131 *offset = memory->base.offset - parent->base.offset;
132 }
133
134 return memory->data + memory->base.offset + memory->base.size == other->data + other->base.offset;
135}
136
137static void gst_allocator_fast_malloc_class_init(GstAllocatorFastMallocClass* klass)
138{
139 auto* gstAllocatorClass = GST_ALLOCATOR_CLASS(klass);
140 gstAllocatorClass->alloc = gstAllocatorFastMallocAlloc;
141 gstAllocatorClass->free = gstAllocatorFastMallocFree;
142}
143
144static void gst_allocator_fast_malloc_init(GstAllocatorFastMalloc* allocator)
145{
146 auto* baseAllocator = GST_ALLOCATOR_CAST(allocator);
147
148 baseAllocator->mem_type = "FastMalloc";
149 baseAllocator->mem_map = reinterpret_cast<GstMemoryMapFunction>(gstAllocatorFastMallocMemMap);
150 baseAllocator->mem_unmap = reinterpret_cast<GstMemoryUnmapFunction>(gstAllocatorFastMallocMemUnmap);
151 baseAllocator->mem_copy = reinterpret_cast<GstMemoryCopyFunction>(gstAllocatorFastMallocMemCopy);
152 baseAllocator->mem_share = reinterpret_cast<GstMemoryShareFunction>(gstAllocatorFastMallocMemShare);
153 baseAllocator->mem_is_span = reinterpret_cast<GstMemoryIsSpanFunction>(gstAllocatorFastMallocMemIsSpan);
154}
155