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);
        }
        NativeArray <byte> GetImageBytesToConvert(
            NativeSlice <byte> imageBytes, Vector2Int sizeInPixels, ref TextureFormat format, ref JobHandle inputDeps)
        {
            // RGBA32 is not supported by CVPixelBuffer, but ARGB32 is, so
            // we offer a conversion for this common case.
            if (format == TextureFormat.RGBA32)
            {
                int numPixels        = sizeInPixels.x * sizeInPixels.y;
                var argb32ImageBytes = new NativeArray <byte>(
                    numPixels * 4,
                    Allocator.Persistent,
                    NativeArrayOptions.UninitializedMemory);

                inputDeps = new ConvertRGBA32ToARGB32Job
                {
                    rgbaImage = imageBytes.SliceConvert <uint>(),
                    argbImage = argb32ImageBytes.Slice().SliceConvert <uint>()
                }.Schedule(numPixels, 64, inputDeps);

                // Format is now ARGB32
                format = TextureFormat.ARGB32;

                return(argb32ImageBytes);
            }

            // No conversion necessary; echo back inputs
            return(default);