mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-15 03:20:30 +00:00
Use Accelerate framework for texture image processing
This commit is contained in:
@@ -2,12 +2,17 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Accelerate;
|
||||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using ObjCRuntime;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using UIKit;
|
||||
|
||||
namespace osu.Framework.iOS.Graphics.Textures
|
||||
@@ -19,7 +24,7 @@ namespace osu.Framework.iOS.Graphics.Textures
|
||||
{
|
||||
}
|
||||
|
||||
protected override Image<TPixel> ImageFromStream<TPixel>(Stream stream)
|
||||
protected override unsafe Image<TPixel> ImageFromStream<TPixel>(Stream stream)
|
||||
{
|
||||
using (var nativeData = NSData.FromStream(stream))
|
||||
{
|
||||
@@ -33,17 +38,64 @@ namespace osu.Framework.iOS.Graphics.Textures
|
||||
int width = (int)uiImage.Size.Width;
|
||||
int height = (int)uiImage.Size.Height;
|
||||
|
||||
// TODO: Use pool/memory when builds success with Xamarin.
|
||||
// Probably at .NET Core 3.1 time frame.
|
||||
byte[] data = new byte[width * height * 4];
|
||||
using (CGBitmapContext textureContext = new CGBitmapContext(data, width, height, 8, width * 4, CGColorSpace.CreateDeviceRGB(), CGImageAlphaInfo.PremultipliedLast))
|
||||
textureContext.DrawImage(new CGRect(0, 0, width, height), uiImage.CGImage);
|
||||
var format = new vImage_CGImageFormat
|
||||
{
|
||||
BitsPerComponent = 8,
|
||||
BitsPerPixel = 32,
|
||||
ColorSpace = CGColorSpace.CreateDeviceRGB().Handle,
|
||||
// notably, iOS generally uses premultiplied alpha when rendering image to pixels via CGBitmapContext or otherwise,
|
||||
// but vImage offers using straight alpha directly without any conversion from our side (by specifying Last instead of PremultipliedLast).
|
||||
BitmapInfo = (CGBitmapFlags)CGImageAlphaInfo.Last,
|
||||
Decode = null,
|
||||
RenderingIntent = CGColorRenderingIntent.Default,
|
||||
};
|
||||
|
||||
var image = Image.LoadPixelData<TPixel>(data, width, height);
|
||||
vImageBuffer accelerateImage = default;
|
||||
|
||||
// perform initial call to retrieve preferred alignment and bytes-per-row values for the given image dimensions.
|
||||
long alignment = (long)vImageBuffer_Init(&accelerateImage, (uint)height, (uint)width, 32, vImageFlags.NoAllocate);
|
||||
Debug.Assert(alignment > 0);
|
||||
|
||||
// allocate aligned memory region to contain image pixel data.
|
||||
int bytesCount = accelerateImage.BytesPerRow * accelerateImage.Height;
|
||||
accelerateImage.Data = (IntPtr)NativeMemory.AlignedAlloc((nuint)(accelerateImage.BytesPerRow * accelerateImage.Height), (nuint)alignment);
|
||||
|
||||
var result = vImageBuffer_InitWithCGImage(&accelerateImage, &format, null, uiImage.CGImage!.Handle, vImageFlags.NoAllocate);
|
||||
Debug.Assert(result == vImageError.NoError);
|
||||
|
||||
var dataSpan = new ReadOnlySpan<byte>(accelerateImage.Data.ToPointer(), bytesCount);
|
||||
|
||||
int stride = accelerateImage.BytesPerRow / 4;
|
||||
var image = Image.LoadPixelData<TPixel>(dataSpan, stride, height);
|
||||
image.Mutate(i => i.Crop(width, height));
|
||||
|
||||
NativeMemory.AlignedFree(accelerateImage.Data.ToPointer());
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Accelerate API
|
||||
|
||||
[DllImport(Constants.AccelerateLibrary)]
|
||||
private static extern unsafe vImageError vImageBuffer_Init(vImageBuffer* buf, uint height, uint width, uint pixelBits, vImageFlags flags);
|
||||
|
||||
[DllImport(Constants.AccelerateLibrary)]
|
||||
private static extern unsafe vImageError vImageBuffer_InitWithCGImage(vImageBuffer* buf, vImage_CGImageFormat* format, nfloat* backgroundColour, NativeHandle image, vImageFlags flags);
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct vImage_CGImageFormat
|
||||
{
|
||||
public uint BitsPerComponent;
|
||||
public uint BitsPerPixel;
|
||||
public NativeHandle ColorSpace;
|
||||
public CGBitmapFlags BitmapInfo;
|
||||
public uint Version;
|
||||
public nfloat* Decode;
|
||||
public CGColorRenderingIntent RenderingIntent;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user