ARKitImageDatabase.cs
8.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
using System;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.Assertions;
namespace UnityEngine.XR.ARKit
{
internal sealed class ARKitImageDatabase : MutableRuntimeReferenceImageLibrary
{
internal IntPtr nativePtr { get; private set; }
~ARKitImageDatabase()
{
Assert.AreNotEqual(nativePtr, IntPtr.Zero);
// Release references
int n = count;
for (int i = 0; i < n; ++i)
{
UnityARKit_ImageDatabase_GetReferenceImage(nativePtr, i).Dispose();
}
UnityARKit_CFRelease(nativePtr);
}
public unsafe ARKitImageDatabase(XRReferenceImageLibrary serializedLibrary)
{
if (serializedLibrary == null)
{
nativePtr = UnityARKit_ImageDatabase_createEmpty();
}
else
{
var managedReferenceImages = new NativeArray<ManagedReferenceImage>(serializedLibrary.count, Allocator.Temp);
for (int i = 0; i < serializedLibrary.count; ++i)
{
managedReferenceImages[i] = new ManagedReferenceImage(serializedLibrary[i]);
}
using (managedReferenceImages)
{
var nativeReturnCode = UnityARKit_ImageDatabase_tryCreateFromResourceGroup(
serializedLibrary.name, serializedLibrary.name.Length, serializedLibrary.guid,
managedReferenceImages.GetUnsafePtr(), managedReferenceImages.Length,
out IntPtr ptr);
switch (nativeReturnCode)
{
case SetReferenceLibraryResult.Success:
nativePtr = ptr;
break;
case SetReferenceLibraryResult.FeatureUnavailable:
throw new InvalidOperationException($"Failed to resolve image library '{serializedLibrary.name}'. This feature only works on versions of ARKit 11.3 and newer.");
case SetReferenceLibraryResult.ResourceDoesNotExist:
throw new InvalidOperationException($"Failed to resolve image library '{serializedLibrary.name}'. There is no matching resource group, or the resource group does not contain any reference images.");
default:
throw new InvalidOperationException($"Unexpected return code {nativeReturnCode} encountered while trying to create a reference image library with name {serializedLibrary.name}.");
}
}
}
}
protected override unsafe JobHandle ScheduleAddImageJobImpl(
NativeSlice<byte> imageBytes,
Vector2Int sizeInPixels,
TextureFormat format,
XRReferenceImage referenceImage,
JobHandle inputDeps)
{
if (!referenceImage.specifySize)
throw new InvalidOperationException("ARKit requires physical dimensions for all reference images.");
// Add a reference to keep the native object alive
// even if we get finalized while a job is running
UnityARKit_CFRetain(nativePtr);
// RGBA32 is not supported by CVPixelBuffer, but ARGB32 is, so
// we offer a conversion for this common case.
var convertedImage = new NativeArray<byte>();
if (format == TextureFormat.RGBA32)
{
int numPixels = sizeInPixels.x * sizeInPixels.y;
convertedImage = new NativeArray<byte>(
numPixels * 4,
Allocator.Persistent,
NativeArrayOptions.UninitializedMemory);
inputDeps = new ConvertRGBA32ToARGB32Job
{
rgbaImage = imageBytes.SliceConvert<uint>(),
argbImage = convertedImage.Slice().SliceConvert<uint>()
}.Schedule(numPixels, 64, inputDeps);
// Format is now ARGB32
format = TextureFormat.ARGB32;
}
// Schedule the actual addition of the image to the database
inputDeps = new AddImageJob
{
image = convertedImage.IsCreated ? new NativeSlice<byte>(convertedImage) : imageBytes,
database = nativePtr,
width = sizeInPixels.x,
height = sizeInPixels.y,
physicalWidth = referenceImage.size.x,
format = format,
managedReferenceImage = new ManagedReferenceImage(referenceImage)
}.Schedule(inputDeps);
// If we had to perform a conversion, then release that memory
if (convertedImage.IsCreated)
{
inputDeps = new DeallocateNativeArrayJob<byte> { array = convertedImage }.Schedule(inputDeps);
}
return inputDeps;
}
static readonly TextureFormat[] k_SupportedFormats =
{
TextureFormat.Alpha8,
TextureFormat.R8,
TextureFormat.R16,
TextureFormat.RFloat,
TextureFormat.RGB24,
TextureFormat.RGBA32,
TextureFormat.ARGB32,
TextureFormat.BGRA32,
};
public override int supportedTextureFormatCount => k_SupportedFormats.Length;
protected override TextureFormat GetSupportedTextureFormatAtImpl(int index) => k_SupportedFormats[index];
protected override XRReferenceImage GetReferenceImageAt(int index)
{
Assert.AreNotEqual(nativePtr, IntPtr.Zero);
return UnityARKit_ImageDatabase_GetReferenceImage(nativePtr, index).ToReferenceImage();
}
public override int count
{
get
{
Assert.AreNotEqual(nativePtr, IntPtr.Zero);
return UnityARKit_ImageDatabase_GetReferenceImageCount(nativePtr);
}
}
struct DeallocateNativeArrayJob<T> : IJob where T : struct
{
[DeallocateOnJobCompletion]
public NativeArray<T> array;
public void Execute() {}
}
struct ConvertRGBA32ToARGB32Job : IJobParallelFor
{
public NativeSlice<uint> rgbaImage;
public NativeSlice<uint> argbImage;
public unsafe void Execute(int index)
{
uint rgba = rgbaImage[index];
argbImage[index] = (rgba << 8) | ((rgba & 0xff000000) >> 24);
}
}
struct AddImageJob : IJob
{
public NativeSlice<byte> image;
public IntPtr database;
public int width;
public int height;
public float physicalWidth;
public TextureFormat format;
public ManagedReferenceImage managedReferenceImage;
public unsafe void Execute()
{
bool success = UnityARKit_ImageDatabase_AddImage(database, image.GetUnsafePtr(), format, width, height, physicalWidth, ref managedReferenceImage);
if (!success)
managedReferenceImage.Dispose();
UnityARKit_CFRelease(database);
}
[DllImport("__Internal")]
static extern unsafe bool UnityARKit_ImageDatabase_AddImage(
IntPtr database, void* bytes, TextureFormat format,
int width, int height, float physicalWidth,
ref ManagedReferenceImage managedReferenceImage);
}
[DllImport("__Internal")]
static extern void UnityARKit_CFRetain(IntPtr ptr);
[DllImport("__Internal")]
static extern void UnityARKit_CFRelease(IntPtr ptr);
[DllImport("__Internal")]
static extern IntPtr UnityARKit_ImageDatabase_createEmpty();
[DllImport("__Internal")]
static unsafe extern SetReferenceLibraryResult UnityARKit_ImageDatabase_tryCreateFromResourceGroup(
[MarshalAs(UnmanagedType.LPWStr)] string name, int nameLength, Guid guid,
void* managedReferenceImages, int managedReferenceImageCount,
out IntPtr ptr);
[DllImport("__Internal")]
static extern ManagedReferenceImage UnityARKit_ImageDatabase_GetReferenceImage(IntPtr database, int index);
[DllImport("__Internal")]
static extern int UnityARKit_ImageDatabase_GetReferenceImageCount(IntPtr database);
}
}