whisper.rn 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/android/build.gradle +2 -1
  2. package/android/gradle.properties +1 -1
  3. package/cpp/ggml-alloc.c +264 -126
  4. package/cpp/ggml-backend-impl.h +4 -1
  5. package/cpp/ggml-backend-reg.cpp +13 -5
  6. package/cpp/ggml-backend.cpp +207 -17
  7. package/cpp/ggml-backend.h +17 -1
  8. package/cpp/ggml-cpu/amx/amx.cpp +4 -2
  9. package/cpp/ggml-cpu/arch/x86/repack.cpp +2 -2
  10. package/cpp/ggml-cpu/arch-fallback.h +0 -4
  11. package/cpp/ggml-cpu/common.h +14 -0
  12. package/cpp/ggml-cpu/ggml-cpu-impl.h +13 -6
  13. package/cpp/ggml-cpu/ggml-cpu.c +48 -41
  14. package/cpp/ggml-cpu/ggml-cpu.cpp +14 -4
  15. package/cpp/ggml-cpu/ops.cpp +518 -767
  16. package/cpp/ggml-cpu/ops.h +2 -0
  17. package/cpp/ggml-cpu/simd-mappings.h +88 -59
  18. package/cpp/ggml-cpu/vec.cpp +161 -20
  19. package/cpp/ggml-cpu/vec.h +400 -51
  20. package/cpp/ggml-cpu.h +1 -1
  21. package/cpp/ggml-impl.h +43 -10
  22. package/cpp/ggml-metal/ggml-metal-common.cpp +446 -0
  23. package/cpp/ggml-metal/ggml-metal-common.h +52 -0
  24. package/cpp/ggml-metal/ggml-metal-context.h +33 -0
  25. package/cpp/ggml-metal/ggml-metal-context.m +600 -0
  26. package/cpp/ggml-metal/ggml-metal-device.cpp +1376 -0
  27. package/cpp/ggml-metal/ggml-metal-device.h +226 -0
  28. package/cpp/ggml-metal/ggml-metal-device.m +1312 -0
  29. package/cpp/ggml-metal/ggml-metal-impl.h +722 -0
  30. package/cpp/ggml-metal/ggml-metal-ops.cpp +3158 -0
  31. package/cpp/ggml-metal/ggml-metal-ops.h +82 -0
  32. package/cpp/ggml-metal/ggml-metal.cpp +718 -0
  33. package/cpp/ggml-metal/ggml-whisper-sim.metallib +0 -0
  34. package/cpp/ggml-metal/ggml-whisper.metallib +0 -0
  35. package/cpp/ggml-metal-impl.h +40 -40
  36. package/cpp/ggml-metal.h +1 -6
  37. package/cpp/ggml-quants.c +1 -0
  38. package/cpp/ggml.c +175 -13
  39. package/cpp/ggml.h +84 -5
  40. package/cpp/jsi/RNWhisperJSI.cpp +2 -0
  41. package/cpp/jsi/ThreadPool.h +3 -3
  42. package/cpp/whisper.cpp +85 -70
  43. package/cpp/whisper.h +1 -0
  44. package/ios/CMakeLists.txt +6 -1
  45. package/ios/RNWhisperVadContext.mm +14 -13
  46. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/Headers/ggml-backend-impl.h +4 -1
  47. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/Headers/ggml-backend.h +17 -1
  48. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/Headers/ggml-cpu.h +1 -1
  49. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/Headers/ggml-impl.h +43 -10
  50. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/Headers/ggml-metal-impl.h +40 -40
  51. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/Headers/ggml-metal.h +1 -6
  52. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/Headers/ggml.h +84 -5
  53. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/Headers/whisper.h +1 -0
  54. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/Info.plist +0 -0
  55. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/ggml-whisper.metallib +0 -0
  56. package/ios/rnwhisper.xcframework/ios-arm64/rnwhisper.framework/rnwhisper +0 -0
  57. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-backend-impl.h +4 -1
  58. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-backend.h +17 -1
  59. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-cpu.h +1 -1
  60. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-impl.h +43 -10
  61. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-metal-impl.h +40 -40
  62. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-metal.h +1 -6
  63. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml.h +84 -5
  64. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/Headers/whisper.h +1 -0
  65. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/Info.plist +0 -0
  66. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/_CodeSignature/CodeResources +1 -1
  67. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/ggml-whisper-sim.metallib +0 -0
  68. package/ios/rnwhisper.xcframework/ios-arm64_x86_64-simulator/rnwhisper.framework/rnwhisper +0 -0
  69. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/Headers/ggml-backend-impl.h +4 -1
  70. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/Headers/ggml-backend.h +17 -1
  71. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/Headers/ggml-cpu.h +1 -1
  72. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/Headers/ggml-impl.h +43 -10
  73. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/Headers/ggml-metal-impl.h +40 -40
  74. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/Headers/ggml-metal.h +1 -6
  75. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/Headers/ggml.h +84 -5
  76. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/Headers/whisper.h +1 -0
  77. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/Info.plist +0 -0
  78. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/ggml-whisper.metallib +0 -0
  79. package/ios/rnwhisper.xcframework/tvos-arm64/rnwhisper.framework/rnwhisper +0 -0
  80. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-backend-impl.h +4 -1
  81. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-backend.h +17 -1
  82. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-cpu.h +1 -1
  83. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-impl.h +43 -10
  84. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-metal-impl.h +40 -40
  85. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml-metal.h +1 -6
  86. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/Headers/ggml.h +84 -5
  87. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/Headers/whisper.h +1 -0
  88. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/Info.plist +0 -0
  89. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/_CodeSignature/CodeResources +1 -1
  90. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/ggml-whisper-sim.metallib +0 -0
  91. package/ios/rnwhisper.xcframework/tvos-arm64_x86_64-simulator/rnwhisper.framework/rnwhisper +0 -0
  92. package/lib/commonjs/version.json +1 -1
  93. package/lib/module/version.json +1 -1
  94. package/package.json +1 -1
  95. package/src/version.json +1 -1
  96. package/whisper-rn.podspec +8 -9
  97. package/cpp/ggml-metal.m +0 -6779
  98. package/cpp/ggml-whisper-sim.metallib +0 -0
  99. package/cpp/ggml-whisper.metallib +0 -0
@@ -0,0 +1,718 @@
1
+ #include "ggml-metal.h"
2
+
3
+ #include "ggml-impl.h"
4
+ #include "ggml-backend-impl.h"
5
+
6
+ #include "ggml-metal-device.h"
7
+ #include "ggml-metal-context.h"
8
+ #include "ggml-metal-ops.h"
9
+
10
+ // globals
11
+
12
+ // initialized in wsp_ggml_backend_metal_reg
13
+ static wsp_ggml_backend_reg g_wsp_ggml_metal_reg;
14
+ static wsp_ggml_backend_device g_wsp_ggml_metal_device;
15
+
16
+ ////////////////////////////////////////////////////////////////////////////////
17
+ // backend interface
18
+ ////////////////////////////////////////////////////////////////////////////////
19
+
20
+ // shared buffer
21
+
22
+ static void wsp_ggml_backend_metal_buffer_shared_free_buffer(wsp_ggml_backend_buffer_t buffer) {
23
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
24
+
25
+ WSP_GGML_ASSERT(wsp_ggml_metal_buffer_is_shared(ctx));
26
+
27
+ wsp_ggml_metal_buffer_free(ctx);
28
+ }
29
+
30
+ static void * wsp_ggml_backend_metal_buffer_shared_get_base(wsp_ggml_backend_buffer_t buffer) {
31
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
32
+
33
+ WSP_GGML_ASSERT(wsp_ggml_metal_buffer_is_shared(ctx));
34
+
35
+ return wsp_ggml_metal_buffer_get_base(ctx);
36
+ }
37
+
38
+ static void wsp_ggml_backend_metal_buffer_shared_memset_tensor(wsp_ggml_backend_buffer_t buffer, wsp_ggml_tensor * tensor, uint8_t value, size_t offset, size_t size) {
39
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
40
+
41
+ WSP_GGML_ASSERT(wsp_ggml_metal_buffer_is_shared(ctx));
42
+
43
+ wsp_ggml_metal_buffer_memset_tensor(ctx, tensor, value, offset, size);
44
+ }
45
+
46
+ static void wsp_ggml_backend_metal_buffer_shared_set_tensor(wsp_ggml_backend_buffer_t buffer, wsp_ggml_tensor * tensor, const void * data, size_t offset, size_t size) {
47
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
48
+
49
+ WSP_GGML_ASSERT(wsp_ggml_metal_buffer_is_shared(ctx));
50
+
51
+ wsp_ggml_metal_buffer_set_tensor(ctx, tensor, data, offset, size);
52
+ }
53
+
54
+ static void wsp_ggml_backend_metal_buffer_shared_get_tensor(wsp_ggml_backend_buffer_t buffer, const wsp_ggml_tensor * tensor, void * data, size_t offset, size_t size) {
55
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
56
+
57
+ WSP_GGML_ASSERT(wsp_ggml_metal_buffer_is_shared(ctx));
58
+
59
+ wsp_ggml_metal_buffer_get_tensor(ctx, tensor, data, offset, size);
60
+ }
61
+
62
+ static bool wsp_ggml_backend_metal_buffer_shared_cpy_tensor(wsp_ggml_backend_buffer_t buffer, const wsp_ggml_tensor * src, wsp_ggml_tensor * dst) {
63
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
64
+
65
+ WSP_GGML_ASSERT(wsp_ggml_metal_buffer_is_shared(ctx));
66
+
67
+ WSP_GGML_UNUSED(buffer);
68
+ WSP_GGML_UNUSED(src);
69
+ WSP_GGML_UNUSED(dst);
70
+
71
+ return false;
72
+ }
73
+
74
+ static void wsp_ggml_backend_metal_buffer_shared_clear(wsp_ggml_backend_buffer_t buffer, uint8_t value) {
75
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
76
+
77
+ WSP_GGML_ASSERT(wsp_ggml_metal_buffer_is_shared(ctx));
78
+
79
+ wsp_ggml_metal_buffer_clear(ctx, value);
80
+ }
81
+
82
+ static wsp_ggml_backend_buffer_i wsp_ggml_backend_metal_buffer_shared_i = {
83
+ /* .free_buffer = */ wsp_ggml_backend_metal_buffer_shared_free_buffer,
84
+ /* .get_base = */ wsp_ggml_backend_metal_buffer_shared_get_base,
85
+ /* .init_tensor = */ NULL,
86
+ /* .memset_tensor = */ wsp_ggml_backend_metal_buffer_shared_memset_tensor,
87
+ /* .set_tensor = */ wsp_ggml_backend_metal_buffer_shared_set_tensor,
88
+ /* .get_tensor = */ wsp_ggml_backend_metal_buffer_shared_get_tensor,
89
+ /* .cpy_tensor = */ wsp_ggml_backend_metal_buffer_shared_cpy_tensor,
90
+ /* .clear = */ wsp_ggml_backend_metal_buffer_shared_clear,
91
+ /* .reset = */ NULL,
92
+ };
93
+
94
+ // private buffer
95
+
96
+ static void wsp_ggml_backend_metal_buffer_private_free_buffer(wsp_ggml_backend_buffer_t buffer) {
97
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
98
+
99
+ WSP_GGML_ASSERT(!wsp_ggml_metal_buffer_is_shared(ctx));
100
+
101
+ wsp_ggml_metal_buffer_free(ctx);
102
+ }
103
+
104
+ static void * wsp_ggml_backend_metal_buffer_private_get_base(wsp_ggml_backend_buffer_t buffer) {
105
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
106
+
107
+ WSP_GGML_ASSERT(!wsp_ggml_metal_buffer_is_shared(ctx));
108
+
109
+ return wsp_ggml_metal_buffer_get_base(ctx);
110
+ }
111
+
112
+ static void wsp_ggml_backend_metal_buffer_private_memset_tensor(wsp_ggml_backend_buffer_t buffer, wsp_ggml_tensor * tensor, uint8_t value, size_t offset, size_t size) {
113
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
114
+
115
+ WSP_GGML_ASSERT(!wsp_ggml_metal_buffer_is_shared(ctx));
116
+
117
+ wsp_ggml_metal_buffer_memset_tensor(ctx, tensor, value, offset, size);
118
+ }
119
+
120
+ static void wsp_ggml_backend_metal_buffer_private_set_tensor(wsp_ggml_backend_buffer_t buffer, wsp_ggml_tensor * tensor, const void * data, size_t offset, size_t size) {
121
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
122
+
123
+ WSP_GGML_ASSERT(!wsp_ggml_metal_buffer_is_shared(ctx));
124
+
125
+ wsp_ggml_metal_buffer_set_tensor(ctx, tensor, data, offset, size);
126
+ }
127
+
128
+ static void wsp_ggml_backend_metal_buffer_private_get_tensor(wsp_ggml_backend_buffer_t buffer, const wsp_ggml_tensor * tensor, void * data, size_t offset, size_t size) {
129
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
130
+
131
+ WSP_GGML_ASSERT(!wsp_ggml_metal_buffer_is_shared(ctx));
132
+
133
+ wsp_ggml_metal_buffer_get_tensor(ctx, tensor, data, offset, size);
134
+ }
135
+
136
+ static bool wsp_ggml_backend_metal_buffer_private_cpy_tensor(wsp_ggml_backend_buffer_t buffer, const wsp_ggml_tensor * src, wsp_ggml_tensor * dst) {
137
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
138
+
139
+ WSP_GGML_ASSERT(!wsp_ggml_metal_buffer_is_shared(ctx));
140
+
141
+ WSP_GGML_UNUSED(buffer);
142
+ WSP_GGML_UNUSED(src);
143
+ WSP_GGML_UNUSED(dst);
144
+
145
+ return false;
146
+ }
147
+
148
+ static void wsp_ggml_backend_metal_buffer_private_clear(wsp_ggml_backend_buffer_t buffer, uint8_t value) {
149
+ wsp_ggml_metal_buffer_t ctx = (wsp_ggml_metal_buffer_t)buffer->context;
150
+
151
+ WSP_GGML_ASSERT(!wsp_ggml_metal_buffer_is_shared(ctx));
152
+
153
+ wsp_ggml_metal_buffer_clear(ctx, value);
154
+ }
155
+
156
+ static wsp_ggml_backend_buffer_i wsp_ggml_backend_metal_buffer_private_i = {
157
+ /* .free_buffer = */ wsp_ggml_backend_metal_buffer_private_free_buffer,
158
+ /* .get_base = */ wsp_ggml_backend_metal_buffer_private_get_base,
159
+ /* .init_tensor = */ NULL,
160
+ /* .memset_tensor = */ wsp_ggml_backend_metal_buffer_private_memset_tensor,
161
+ /* .set_tensor = */ wsp_ggml_backend_metal_buffer_private_set_tensor,
162
+ /* .get_tensor = */ wsp_ggml_backend_metal_buffer_private_get_tensor,
163
+ /* .cpy_tensor = */ wsp_ggml_backend_metal_buffer_private_cpy_tensor,
164
+ /* .clear = */ wsp_ggml_backend_metal_buffer_private_clear,
165
+ /* .reset = */ NULL,
166
+ };
167
+
168
+ //
169
+ // buffer types
170
+ //
171
+
172
+ // common method for allocating shread or private Metal buffers
173
+ static wsp_ggml_backend_buffer_t wsp_ggml_backend_metal_buffer_type_alloc_buffer(wsp_ggml_backend_buffer_type_t buft, size_t size, bool shared) {
174
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)buft->device->context;
175
+ wsp_ggml_metal_buffer_t res = wsp_ggml_metal_buffer_init(ctx_dev, size, shared);
176
+
177
+ wsp_ggml_backend_buffer_i buf_i = wsp_ggml_metal_buffer_is_shared(res)
178
+ ? wsp_ggml_backend_metal_buffer_shared_i
179
+ : wsp_ggml_backend_metal_buffer_private_i;
180
+
181
+ return wsp_ggml_backend_buffer_init(buft, buf_i, res, size);
182
+ }
183
+
184
+ static size_t wsp_ggml_backend_metal_buffer_type_get_alloc_size(wsp_ggml_backend_buffer_type_t buft, const wsp_ggml_tensor * tensor) {
185
+ size_t res = wsp_ggml_nbytes(tensor);
186
+
187
+ // some operations require additional memory for fleeting data:
188
+ switch (tensor->op) {
189
+ case WSP_GGML_OP_MUL_MAT_ID:
190
+ {
191
+ res += wsp_ggml_metal_op_mul_mat_id_extra_tpe(tensor);
192
+ res += wsp_ggml_metal_op_mul_mat_id_extra_ids(tensor);
193
+ } break;
194
+ case WSP_GGML_OP_FLASH_ATTN_EXT:
195
+ {
196
+ if (wsp_ggml_metal_op_flash_attn_ext_use_vec(tensor)) {
197
+ res += wsp_ggml_metal_op_flash_attn_ext_extra_tmp(tensor);
198
+ }
199
+ } break;
200
+ default:
201
+ break;
202
+ }
203
+
204
+ return res;
205
+
206
+ WSP_GGML_UNUSED(buft);
207
+ }
208
+
209
+ // default (shared) buffer type
210
+
211
+ static const char * wsp_ggml_backend_metal_buffer_type_shared_get_name(wsp_ggml_backend_buffer_type_t buft) {
212
+ return "Metal";
213
+
214
+ WSP_GGML_UNUSED(buft);
215
+ }
216
+
217
+ static wsp_ggml_backend_buffer_t wsp_ggml_backend_metal_buffer_type_shared_alloc_buffer(wsp_ggml_backend_buffer_type_t buft, size_t size) {
218
+ return wsp_ggml_backend_metal_buffer_type_alloc_buffer(buft, size, true);
219
+ }
220
+
221
+ static size_t wsp_ggml_backend_metal_buffer_type_shared_get_alignment(wsp_ggml_backend_buffer_type_t buft) {
222
+ return 32;
223
+
224
+ WSP_GGML_UNUSED(buft);
225
+ }
226
+
227
+ static size_t wsp_ggml_backend_metal_buffer_type_shared_get_max_size(wsp_ggml_backend_buffer_type_t buft) {
228
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)buft->device->context;
229
+
230
+ return wsp_ggml_metal_device_get_props(ctx_dev)->max_buffer_size;
231
+ }
232
+
233
+ static size_t wsp_ggml_backend_metal_buffer_type_shared_get_alloc_size(wsp_ggml_backend_buffer_type_t buft, const wsp_ggml_tensor * tensor) {
234
+ return wsp_ggml_backend_metal_buffer_type_get_alloc_size(buft, tensor);
235
+ }
236
+
237
+ static bool wsp_ggml_backend_metal_buffer_type_shared_is_host(wsp_ggml_backend_buffer_type_t buft) {
238
+ return false;
239
+
240
+ WSP_GGML_UNUSED(buft);
241
+ }
242
+
243
+ static wsp_ggml_backend_buffer_type_t wsp_ggml_backend_metal_buffer_type_shared(void) {
244
+ static wsp_ggml_backend_buffer_type wsp_ggml_backend_buffer_type_metal = {
245
+ /* .iface = */ {
246
+ /* .get_name = */ wsp_ggml_backend_metal_buffer_type_shared_get_name,
247
+ /* .alloc_buffer = */ wsp_ggml_backend_metal_buffer_type_shared_alloc_buffer,
248
+ /* .get_alignment = */ wsp_ggml_backend_metal_buffer_type_shared_get_alignment,
249
+ /* .get_max_size = */ wsp_ggml_backend_metal_buffer_type_shared_get_max_size,
250
+ /* .get_alloc_size = */ wsp_ggml_backend_metal_buffer_type_shared_get_alloc_size,
251
+ /* .is_host = */ wsp_ggml_backend_metal_buffer_type_shared_is_host,
252
+ },
253
+ /* .device = */ &g_wsp_ggml_metal_device,
254
+ /* .context = */ NULL,
255
+ };
256
+
257
+ return &wsp_ggml_backend_buffer_type_metal;
258
+ }
259
+
260
+ // default (private) buffer type
261
+
262
+ static const char * wsp_ggml_backend_metal_buffer_type_private_get_name(wsp_ggml_backend_buffer_type_t buft) {
263
+ return "Metal_Private";
264
+
265
+ WSP_GGML_UNUSED(buft);
266
+ }
267
+
268
+ static wsp_ggml_backend_buffer_t wsp_ggml_backend_metal_buffer_type_private_alloc_buffer(wsp_ggml_backend_buffer_type_t buft, size_t size) {
269
+ return wsp_ggml_backend_metal_buffer_type_alloc_buffer(buft, size, false);
270
+ }
271
+
272
+ static size_t wsp_ggml_backend_metal_buffer_type_private_get_alignment(wsp_ggml_backend_buffer_type_t buft) {
273
+ return 32;
274
+
275
+ WSP_GGML_UNUSED(buft);
276
+ }
277
+
278
+ static size_t wsp_ggml_backend_metal_buffer_type_private_get_max_size(wsp_ggml_backend_buffer_type_t buft) {
279
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)buft->device->context;
280
+
281
+ return wsp_ggml_metal_device_get_props(ctx_dev)->max_buffer_size;
282
+ }
283
+
284
+ static size_t wsp_ggml_backend_metal_buffer_type_private_get_alloc_size(wsp_ggml_backend_buffer_type_t buft, const wsp_ggml_tensor * tensor) {
285
+ return wsp_ggml_backend_metal_buffer_type_get_alloc_size(buft, tensor);
286
+ }
287
+
288
+ static bool wsp_ggml_backend_metal_buffer_type_private_is_host(wsp_ggml_backend_buffer_type_t buft) {
289
+ return false;
290
+
291
+ WSP_GGML_UNUSED(buft);
292
+ }
293
+
294
+ static wsp_ggml_backend_buffer_type_t wsp_ggml_backend_metal_buffer_type_private(void) {
295
+ static wsp_ggml_backend_buffer_type wsp_ggml_backend_buffer_type_metal = {
296
+ /* .iface = */ {
297
+ /* .get_name = */ wsp_ggml_backend_metal_buffer_type_private_get_name,
298
+ /* .alloc_buffer = */ wsp_ggml_backend_metal_buffer_type_private_alloc_buffer,
299
+ /* .get_alignment = */ wsp_ggml_backend_metal_buffer_type_private_get_alignment,
300
+ /* .get_max_size = */ wsp_ggml_backend_metal_buffer_type_private_get_max_size,
301
+ /* .get_alloc_size = */ wsp_ggml_backend_metal_buffer_type_private_get_alloc_size,
302
+ /* .is_host = */ wsp_ggml_backend_metal_buffer_type_private_is_host,
303
+ },
304
+ /* .device = */ &g_wsp_ggml_metal_device,
305
+ /* .context = */ NULL,
306
+ };
307
+
308
+ return &wsp_ggml_backend_buffer_type_metal;
309
+ }
310
+
311
+ // mapped buffer type
312
+
313
+ static const char * wsp_ggml_backend_metal_buffer_type_mapped_get_name(wsp_ggml_backend_buffer_type_t buft) {
314
+ return "Metal_Mapped";
315
+
316
+ WSP_GGML_UNUSED(buft);
317
+ }
318
+
319
+ static wsp_ggml_backend_buffer_t wsp_ggml_backend_metal_buffer_type_mapped_alloc_buffer(wsp_ggml_backend_buffer_type_t buft, size_t size) {
320
+ // for mapped buffers, prefer shared memory
321
+ return wsp_ggml_backend_metal_buffer_type_alloc_buffer(buft, size, true);
322
+ }
323
+
324
+ static size_t wsp_ggml_backend_metal_buffer_type_mapped_get_alignment(wsp_ggml_backend_buffer_type_t buft) {
325
+ return 32;
326
+
327
+ WSP_GGML_UNUSED(buft);
328
+ }
329
+
330
+ static size_t wsp_ggml_backend_metal_buffer_type_mapped_get_max_size(wsp_ggml_backend_buffer_type_t buft) {
331
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)buft->device->context;
332
+
333
+ return wsp_ggml_metal_device_get_props(ctx_dev)->max_buffer_size;
334
+ }
335
+
336
+ static size_t wsp_ggml_backend_metal_buffer_type_mapped_get_alloc_size(wsp_ggml_backend_buffer_type_t buft, const wsp_ggml_tensor * tensor) {
337
+ return wsp_ggml_backend_metal_buffer_type_get_alloc_size(buft, tensor);
338
+ }
339
+
340
+ static bool wsp_ggml_backend_metal_buffer_type_mapped_is_host(wsp_ggml_backend_buffer_type_t buft) {
341
+ return false;
342
+
343
+ WSP_GGML_UNUSED(buft);
344
+ }
345
+
346
+ static wsp_ggml_backend_buffer_type_t wsp_ggml_backend_metal_buffer_type_mapped(void) {
347
+ // note: not obvious, but this buffer type still needs to implement .alloc_buffer:
348
+ // https://github.com/ggml-org/llama.cpp/pull/15832#discussion_r2333177099
349
+ static wsp_ggml_backend_buffer_type wsp_ggml_backend_buffer_type_mapped_metal = {
350
+ /* .iface = */ {
351
+ /* .get_name = */ wsp_ggml_backend_metal_buffer_type_mapped_get_name,
352
+ /* .alloc_buffer = */ wsp_ggml_backend_metal_buffer_type_mapped_alloc_buffer,
353
+ /* .get_alignment = */ wsp_ggml_backend_metal_buffer_type_mapped_get_alignment,
354
+ /* .get_max_size = */ wsp_ggml_backend_metal_buffer_type_mapped_get_max_size,
355
+ /* .get_alloc_size = */ wsp_ggml_backend_metal_buffer_type_mapped_get_alloc_size,
356
+ /* .is_host = */ wsp_ggml_backend_metal_buffer_type_mapped_is_host,
357
+ },
358
+ /* .device = */ &g_wsp_ggml_metal_device,
359
+ /* .context = */ NULL,
360
+ };
361
+
362
+ return &wsp_ggml_backend_buffer_type_mapped_metal;
363
+ }
364
+
365
+ // backend
366
+
367
+ static const char * wsp_ggml_backend_metal_name(wsp_ggml_backend_t backend) {
368
+ return "Metal";
369
+
370
+ WSP_GGML_UNUSED(backend);
371
+ }
372
+
373
+ static void wsp_ggml_backend_metal_free(wsp_ggml_backend_t backend) {
374
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
375
+
376
+ // wait for any ongoing async operations to finish
377
+ wsp_ggml_metal_synchronize(ctx);
378
+
379
+ wsp_ggml_metal_free(ctx);
380
+
381
+ free(backend);
382
+ }
383
+
384
+ static void wsp_ggml_backend_metal_synchronize(wsp_ggml_backend_t backend) {
385
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
386
+
387
+ wsp_ggml_metal_synchronize(ctx);
388
+ }
389
+
390
+ static void wsp_ggml_backend_metal_set_tensor_async(wsp_ggml_backend_t backend, wsp_ggml_tensor * tensor, const void * data, size_t offset, size_t size) {
391
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
392
+
393
+ wsp_ggml_metal_set_tensor_async(ctx, tensor, data, offset, size);
394
+ }
395
+
396
+ static void wsp_ggml_backend_metal_get_tensor_async(wsp_ggml_backend_t backend, const wsp_ggml_tensor * tensor, void * data, size_t offset, size_t size) {
397
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
398
+
399
+ wsp_ggml_metal_get_tensor_async(ctx, tensor, data, offset, size);
400
+ }
401
+
402
+ static bool wsp_ggml_backend_metal_cpy_tensor_async(wsp_ggml_backend_t backend_src, wsp_ggml_backend_t backend_dst, const wsp_ggml_tensor * src, wsp_ggml_tensor * dst) {
403
+ return false;
404
+
405
+ WSP_GGML_UNUSED(backend_src);
406
+ WSP_GGML_UNUSED(backend_dst);
407
+ WSP_GGML_UNUSED(src);
408
+ WSP_GGML_UNUSED(dst);
409
+ }
410
+
411
+ static enum wsp_ggml_status wsp_ggml_backend_metal_graph_compute(wsp_ggml_backend_t backend, wsp_ggml_cgraph * cgraph) {
412
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
413
+
414
+ return wsp_ggml_metal_graph_compute(ctx, cgraph);
415
+ }
416
+
417
+ static void wsp_ggml_backend_metal_graph_optimize(wsp_ggml_backend_t backend, wsp_ggml_cgraph * cgraph) {
418
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
419
+
420
+ wsp_ggml_metal_graph_optimize(ctx, cgraph);
421
+ }
422
+
423
+ static void wsp_ggml_backend_metal_set_n_cb(wsp_ggml_backend_t backend, int n_cb) {
424
+ WSP_GGML_ASSERT(wsp_ggml_backend_is_metal(backend));
425
+
426
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
427
+
428
+ wsp_ggml_metal_set_n_cb(ctx, n_cb);
429
+
430
+ }
431
+
432
+ static wsp_ggml_backend_i wsp_ggml_backend_metal_i = {
433
+ /* .get_name = */ wsp_ggml_backend_metal_name,
434
+ /* .free = */ wsp_ggml_backend_metal_free,
435
+ /* .set_tensor_async = */ wsp_ggml_backend_metal_set_tensor_async,
436
+ /* .get_tensor_async = */ wsp_ggml_backend_metal_get_tensor_async,
437
+ /* .cpy_tensor_async = */ wsp_ggml_backend_metal_cpy_tensor_async, // only needed for multi-GPU setups
438
+ /* .synchronize = */ wsp_ggml_backend_metal_synchronize,
439
+ /* .graph_plan_create = */ NULL,
440
+ /* .graph_plan_free = */ NULL,
441
+ /* .graph_plan_update = */ NULL,
442
+ /* .graph_plan_compute = */ NULL,
443
+ /* .graph_compute = */ wsp_ggml_backend_metal_graph_compute,
444
+
445
+ // the events API is needed only for multi-GPU setups, so likely no need to implement it for Metal
446
+ // in any case, these docs seem relevant if we ever decide to implement it:
447
+ // https://developer.apple.com/documentation/metal/mtlcommandbuffer#Synchronizing-Passes-with-Events
448
+ /* .event_record = */ NULL,
449
+ /* .event_wait = */ NULL,
450
+ /* .graph_optimize = */ wsp_ggml_backend_metal_graph_optimize,
451
+ };
452
+
453
+ static wsp_ggml_guid_t wsp_ggml_backend_metal_guid(void) {
454
+ static wsp_ggml_guid guid = { 0x81, 0xa1, 0x8b, 0x1e, 0x71, 0xec, 0x79, 0xed, 0x2b, 0x85, 0xdc, 0x8a, 0x61, 0x98, 0x30, 0xe6 };
455
+ return &guid;
456
+ }
457
+
458
+ wsp_ggml_backend_t wsp_ggml_backend_metal_init(void) {
459
+ wsp_ggml_backend_dev_t dev = wsp_ggml_backend_reg_dev_get(wsp_ggml_backend_metal_reg(), 0);
460
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)dev->context;
461
+
462
+ wsp_ggml_metal_t ctx = wsp_ggml_metal_init(ctx_dev);
463
+ if (ctx == NULL) {
464
+ WSP_GGML_LOG_ERROR("%s: error: failed to allocate context\n", __func__);
465
+ return NULL;
466
+ }
467
+
468
+ wsp_ggml_backend_t backend = (wsp_ggml_backend_t) malloc(sizeof(wsp_ggml_backend));
469
+
470
+ *backend = {
471
+ /* .guid = */ wsp_ggml_backend_metal_guid(),
472
+ /* .interface = */ wsp_ggml_backend_metal_i,
473
+ /* .device = */ dev,
474
+ /* .context = */ ctx,
475
+ };
476
+
477
+ wsp_ggml_backend_metal_set_n_cb(backend, 1);
478
+
479
+ return backend;
480
+ }
481
+
482
+ bool wsp_ggml_backend_is_metal(wsp_ggml_backend_t backend) {
483
+ return backend != NULL && wsp_ggml_guid_matches(backend->guid, wsp_ggml_backend_metal_guid());
484
+ }
485
+
486
+ void wsp_ggml_backend_metal_set_abort_callback(wsp_ggml_backend_t backend, wsp_ggml_abort_callback abort_callback, void * user_data) {
487
+ WSP_GGML_ASSERT(wsp_ggml_backend_is_metal(backend));
488
+
489
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
490
+
491
+ wsp_ggml_metal_set_abort_callback(ctx, abort_callback, user_data);
492
+ }
493
+
494
+ bool wsp_ggml_backend_metal_supports_family(wsp_ggml_backend_t backend, int family) {
495
+ WSP_GGML_ASSERT(wsp_ggml_backend_is_metal(backend));
496
+
497
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
498
+
499
+ return wsp_ggml_metal_supports_family(ctx, family);
500
+ }
501
+
502
+ void wsp_ggml_backend_metal_capture_next_compute(wsp_ggml_backend_t backend) {
503
+ WSP_GGML_ASSERT(wsp_ggml_backend_is_metal(backend));
504
+
505
+ wsp_ggml_metal_t ctx = (wsp_ggml_metal_t)backend->context;
506
+
507
+ wsp_ggml_metal_capture_next_compute(ctx);
508
+ }
509
+
510
+ // backend device
511
+
512
+ static const char * wsp_ggml_backend_metal_device_get_name(wsp_ggml_backend_dev_t dev) {
513
+ return "Metal";
514
+
515
+ WSP_GGML_UNUSED(dev);
516
+ }
517
+
518
+ static const char * wsp_ggml_backend_metal_device_get_description(wsp_ggml_backend_dev_t dev) {
519
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)dev->context;
520
+
521
+ return wsp_ggml_metal_device_get_props(ctx_dev)->name;
522
+ }
523
+
524
+ static void wsp_ggml_backend_metal_device_get_memory(wsp_ggml_backend_dev_t dev, size_t * free, size_t * total) {
525
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)dev->context;
526
+
527
+ wsp_ggml_metal_device_get_memory(ctx_dev, free, total);
528
+ }
529
+
530
+ static enum wsp_ggml_backend_dev_type wsp_ggml_backend_metal_device_get_type(wsp_ggml_backend_dev_t dev) {
531
+ return WSP_GGML_BACKEND_DEVICE_TYPE_GPU;
532
+
533
+ WSP_GGML_UNUSED(dev);
534
+ }
535
+
536
+ static void wsp_ggml_backend_metal_device_get_props(wsp_ggml_backend_dev_t dev, wsp_ggml_backend_dev_props * props) {
537
+ props->name = wsp_ggml_backend_metal_device_get_name(dev);
538
+ props->description = wsp_ggml_backend_metal_device_get_description(dev);
539
+ props->type = wsp_ggml_backend_metal_device_get_type(dev);
540
+
541
+ wsp_ggml_backend_metal_device_get_memory(dev, &props->memory_free, &props->memory_total);
542
+
543
+ props->caps = {
544
+ /* .async = */ true,
545
+ /* .host_buffer = */ false,
546
+ /* .buffer_from_host_ptr = */ true,
547
+ /* .events = */ false,
548
+ };
549
+ }
550
+
551
+ static wsp_ggml_backend_t wsp_ggml_backend_metal_device_init(wsp_ggml_backend_dev_t dev, const char * params) {
552
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)dev->context;
553
+
554
+ wsp_ggml_metal_t ctx = wsp_ggml_metal_init(ctx_dev);
555
+ if (ctx == NULL) {
556
+ WSP_GGML_LOG_ERROR("%s: error: failed to allocate context\n", __func__);
557
+ return NULL;
558
+ }
559
+
560
+ wsp_ggml_backend_t backend = (wsp_ggml_backend_t) malloc(sizeof(wsp_ggml_backend));
561
+
562
+ *backend = {
563
+ /* .guid = */ wsp_ggml_backend_metal_guid(),
564
+ /* .interface = */ wsp_ggml_backend_metal_i,
565
+ /* .device = */ dev,
566
+ /* .context = */ ctx,
567
+ };
568
+
569
+ wsp_ggml_backend_metal_set_n_cb(backend, 1);
570
+
571
+ return backend;
572
+
573
+ WSP_GGML_UNUSED(params);
574
+ }
575
+
576
+ static wsp_ggml_backend_buffer_type_t wsp_ggml_backend_metal_device_get_buffer_type(wsp_ggml_backend_dev_t dev) {
577
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)dev->context;
578
+
579
+ const wsp_ggml_metal_device_props * props_dev = wsp_ggml_metal_device_get_props(ctx_dev);
580
+
581
+ return props_dev->use_shared_buffers ? wsp_ggml_backend_metal_buffer_type_shared() : wsp_ggml_backend_metal_buffer_type_private();
582
+ }
583
+
584
+ static wsp_ggml_backend_buffer_t wsp_ggml_backend_metal_device_buffer_mapped(wsp_ggml_backend_dev_t dev, void * ptr, size_t size, size_t max_tensor_size) {
585
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)dev->context;
586
+
587
+ wsp_ggml_metal_buffer_t res = wsp_ggml_metal_buffer_map(ctx_dev, ptr, size, max_tensor_size);
588
+
589
+ return wsp_ggml_backend_buffer_init(wsp_ggml_backend_metal_buffer_type_mapped(), wsp_ggml_backend_metal_buffer_shared_i, res, size);
590
+ }
591
+
592
+ static bool wsp_ggml_backend_metal_device_supports_op(wsp_ggml_backend_dev_t dev, const wsp_ggml_tensor * op) {
593
+ wsp_ggml_metal_device_t ctx_dev = (wsp_ggml_metal_device_t)dev->context;
594
+
595
+ return wsp_ggml_metal_device_supports_op(ctx_dev, op);
596
+ }
597
+
598
+ static bool wsp_ggml_backend_metal_device_supports_buft(wsp_ggml_backend_dev_t dev, wsp_ggml_backend_buffer_type_t buft) {
599
+ return
600
+ buft->iface.get_name == wsp_ggml_backend_metal_buffer_type_shared_get_name ||
601
+ buft->iface.get_name == wsp_ggml_backend_metal_buffer_type_private_get_name ||
602
+ buft->iface.get_name == wsp_ggml_backend_metal_buffer_type_mapped_get_name;
603
+
604
+ WSP_GGML_UNUSED(dev);
605
+ }
606
+
607
+ static int64_t get_op_batch_size(const wsp_ggml_tensor * op) {
608
+ switch (op->op) {
609
+ case WSP_GGML_OP_MUL_MAT:
610
+ return op->ne[1];
611
+ case WSP_GGML_OP_MUL_MAT_ID:
612
+ return op->ne[2];
613
+ default:
614
+ return wsp_ggml_nrows(op);
615
+ }
616
+ }
617
+
618
+ static bool wsp_ggml_backend_metal_device_offload_op(wsp_ggml_backend_dev_t dev, const wsp_ggml_tensor * op) {
619
+ const int min_batch_size = 32;
620
+
621
+ return (op->op == WSP_GGML_OP_MUL_MAT ||
622
+ op->op == WSP_GGML_OP_MUL_MAT_ID) &&
623
+ get_op_batch_size(op) >= min_batch_size;
624
+
625
+ WSP_GGML_UNUSED(dev);
626
+ WSP_GGML_UNUSED(op);
627
+ }
628
+
629
+ static wsp_ggml_backend_device_i wsp_ggml_backend_metal_device_i = {
630
+ /* .get_name = */ wsp_ggml_backend_metal_device_get_name,
631
+ /* .get_description = */ wsp_ggml_backend_metal_device_get_description,
632
+ /* .get_memory = */ wsp_ggml_backend_metal_device_get_memory,
633
+ /* .get_type = */ wsp_ggml_backend_metal_device_get_type,
634
+ /* .get_props = */ wsp_ggml_backend_metal_device_get_props,
635
+ /* .init_backend = */ wsp_ggml_backend_metal_device_init,
636
+ /* .get_buffer_type = */ wsp_ggml_backend_metal_device_get_buffer_type,
637
+ /* .get_host_buffer_type = */ NULL,
638
+ /* .buffer_from_host_ptr = */ wsp_ggml_backend_metal_device_buffer_mapped,
639
+ /* .supports_op = */ wsp_ggml_backend_metal_device_supports_op,
640
+ /* .supports_buft = */ wsp_ggml_backend_metal_device_supports_buft,
641
+ /* .offload_op = */ wsp_ggml_backend_metal_device_offload_op,
642
+ /* .event_new = */ NULL,
643
+ /* .event_free = */ NULL,
644
+ /* .event_synchronize = */ NULL,
645
+ };
646
+
647
+ // backend registry
648
+
649
+ static const char * wsp_ggml_backend_metal_reg_get_name(wsp_ggml_backend_reg_t reg) {
650
+ return "Metal";
651
+
652
+ WSP_GGML_UNUSED(reg);
653
+ }
654
+
655
+ static size_t wsp_ggml_backend_metal_reg_device_count(wsp_ggml_backend_reg_t reg) {
656
+ return 1;
657
+
658
+ WSP_GGML_UNUSED(reg);
659
+ }
660
+
661
+ static wsp_ggml_backend_dev_t wsp_ggml_backend_metal_reg_device_get(wsp_ggml_backend_reg_t reg, size_t index) {
662
+ WSP_GGML_ASSERT(index == 0);
663
+
664
+ return &g_wsp_ggml_metal_device;
665
+
666
+ WSP_GGML_UNUSED(reg);
667
+ WSP_GGML_UNUSED(index);
668
+ }
669
+
670
+ static wsp_ggml_backend_feature g_wsp_ggml_backend_metal_features[] = {
671
+ #if defined(WSP_GGML_METAL_EMBED_LIBRARY)
672
+ { "EMBED_LIBRARY", "1" },
673
+ #endif
674
+ { NULL, NULL },
675
+ };
676
+
677
+ static wsp_ggml_backend_feature * wsp_ggml_backend_metal_get_features(wsp_ggml_backend_reg_t reg) {
678
+ return g_wsp_ggml_backend_metal_features;
679
+
680
+ WSP_GGML_UNUSED(reg);
681
+ }
682
+
683
+ static void * wsp_ggml_backend_metal_get_proc_address(wsp_ggml_backend_reg_t reg, const char * name) {
684
+ if (strcmp(name, "wsp_ggml_backend_get_features") == 0) {
685
+ return (void *)wsp_ggml_backend_metal_get_features;
686
+ }
687
+
688
+ return NULL;
689
+
690
+ WSP_GGML_UNUSED(reg);
691
+ }
692
+
693
+ static wsp_ggml_backend_reg_i wsp_ggml_backend_metal_reg_i = {
694
+ /* .get_name = */ wsp_ggml_backend_metal_reg_get_name,
695
+ /* .device_count = */ wsp_ggml_backend_metal_reg_device_count,
696
+ /* .device_get = */ wsp_ggml_backend_metal_reg_device_get,
697
+ /* .get_proc_address = */ wsp_ggml_backend_metal_get_proc_address,
698
+ };
699
+
700
+ wsp_ggml_backend_reg_t wsp_ggml_backend_metal_reg(void) {
701
+ {
702
+ g_wsp_ggml_metal_reg = {
703
+ /* .api_version = */ WSP_GGML_BACKEND_API_VERSION,
704
+ /* .iface = */ wsp_ggml_backend_metal_reg_i,
705
+ /* .context = */ NULL,
706
+ };
707
+
708
+ g_wsp_ggml_metal_device = {
709
+ /* .iface = */ wsp_ggml_backend_metal_device_i,
710
+ /* .reg = */ &g_wsp_ggml_metal_reg,
711
+ /* .context = */ wsp_ggml_metal_device_get(),
712
+ };
713
+ }
714
+
715
+ return &g_wsp_ggml_metal_reg;
716
+ }
717
+
718
+ WSP_GGML_BACKEND_DL_IMPL(wsp_ggml_backend_metal_reg)