Improved the means for creating surfaces around textures. #413

This commit is contained in:
Matthew Leibowitz 2018-01-13 17:19:18 +02:00
Родитель b601851ca1
Коммит cdeb6b67ec
12 изменённых файлов: 404 добавлений и 59 удалений

Просмотреть файл

@ -1839,6 +1839,21 @@ namespace SkiaSharp
RenderTarget = 1,
}
[StructLayout(LayoutKind.Sequential)]
public struct GRGlTextureInfo {
private uint fTarget;
private uint fID;
public uint Target {
get { return fTarget; }
set { fTarget = value; }
}
public uint Id {
get { return fID; }
set { fID = value; }
}
};
[StructLayout(LayoutKind.Sequential)]
public struct GRBackendTextureDesc {
private GRBackendTextureDescFlags flags;
@ -1879,6 +1894,16 @@ namespace SkiaSharp
}
}
public struct GRGlBackendTextureDesc {
public GRBackendTextureDescFlags Flags { get; set; }
public GRSurfaceOrigin Origin { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public GRPixelConfig Config { get; set; }
public int SampleCount { get; set; }
public GRGlTextureInfo TextureHandle { get; set; }
}
public enum GRContextOptionsGpuPathRenderers {
None = 0,
DashLine = 1 << 0,

Просмотреть файл

@ -202,6 +202,39 @@ namespace SkiaSharp
return GetObject<SKImage> (handle);
}
public static SKImage FromTexture (GRContext context, GRGlBackendTextureDesc desc)
{
return FromTexture (context, desc, SKAlphaType.Premul);
}
public static SKImage FromTexture (GRContext context, GRGlBackendTextureDesc desc, SKAlphaType alpha)
{
return FromTexture (context, desc, alpha, null);
}
public static SKImage FromTexture (GRContext context, GRGlBackendTextureDesc desc, SKAlphaType alpha, SKImageTextureReleaseDelegate releaseProc)
{
return FromTexture (context, desc, alpha, releaseProc, null);
}
public static SKImage FromTexture (GRContext context, GRGlBackendTextureDesc desc, SKAlphaType alpha, SKImageTextureReleaseDelegate releaseProc, object releaseContext)
{
unsafe {
var h = desc.TextureHandle;
var hPtr = &h;
var d = new GRBackendTextureDesc {
Flags = desc.Flags,
Origin = desc.Origin,
Width = desc.Width,
Height = desc.Height,
Config = desc.Config,
SampleCount = desc.SampleCount,
TextureHandle = (IntPtr)hPtr,
};
return FromTexture (context, d, alpha, releaseProc, releaseContext);
}
}
public static SKImage FromTexture (GRContext context, GRBackendTextureDesc desc)
{
return FromTexture (context, desc, SKAlphaType.Premul);
@ -230,6 +263,29 @@ namespace SkiaSharp
}
}
public static SKImage FromAdoptedTexture (GRContext context, GRGlBackendTextureDesc desc)
{
return FromAdoptedTexture (context, desc, SKAlphaType.Premul);
}
public static SKImage FromAdoptedTexture (GRContext context, GRGlBackendTextureDesc desc, SKAlphaType alpha)
{
unsafe {
var h = desc.TextureHandle;
var hPtr = &h;
var d = new GRBackendTextureDesc {
Flags = desc.Flags,
Origin = desc.Origin,
Width = desc.Width,
Height = desc.Height,
Config = desc.Config,
SampleCount = desc.SampleCount,
TextureHandle = (IntPtr)hPtr,
};
return FromAdoptedTexture (context, d, alpha);
}
}
public static SKImage FromAdoptedTexture (GRContext context, GRBackendTextureDesc desc)
{
return FromAdoptedTexture (context, desc, SKAlphaType.Premul);

Просмотреть файл

@ -74,6 +74,81 @@ namespace SkiaSharp
return GetObject<SKSurface> (SkiaApi.sk_surface_new_backend_render_target (context.Handle, ref desc, IntPtr.Zero));
}
public static SKSurface Create (GRContext context, GRGlBackendTextureDesc desc, SKSurfaceProps props)
{
unsafe {
var h = desc.TextureHandle;
var hPtr = &h;
var d = new GRBackendTextureDesc {
Flags = desc.Flags,
Origin = desc.Origin,
Width = desc.Width,
Height = desc.Height,
Config = desc.Config,
SampleCount = desc.SampleCount,
TextureHandle = (IntPtr)hPtr,
};
return Create (context, d, props);
}
}
public static SKSurface Create (GRContext context, GRGlBackendTextureDesc desc)
{
unsafe {
var h = desc.TextureHandle;
var hPtr = &h;
var d = new GRBackendTextureDesc
{
Flags = desc.Flags,
Origin = desc.Origin,
Width = desc.Width,
Height = desc.Height,
Config = desc.Config,
SampleCount = desc.SampleCount,
TextureHandle = (IntPtr)hPtr,
};
return Create (context, d);
}
}
public static SKSurface CreateAsRenderTarget (GRContext context, GRGlBackendTextureDesc desc, SKSurfaceProps props)
{
unsafe {
var h = desc.TextureHandle;
var hPtr = &h;
var d = new GRBackendTextureDesc
{
Flags = desc.Flags,
Origin = desc.Origin,
Width = desc.Width,
Height = desc.Height,
Config = desc.Config,
SampleCount = desc.SampleCount,
TextureHandle = (IntPtr)hPtr,
};
return CreateAsRenderTarget (context, d, props);
}
}
public static SKSurface CreateAsRenderTarget (GRContext context, GRGlBackendTextureDesc desc)
{
unsafe {
var h = desc.TextureHandle;
var hPtr = &h;
var d = new GRBackendTextureDesc
{
Flags = desc.Flags,
Origin = desc.Origin,
Width = desc.Width,
Height = desc.Height,
Config = desc.Config,
SampleCount = desc.SampleCount,
TextureHandle = (IntPtr)hPtr,
};
return CreateAsRenderTarget (context, d);
}
}
public static SKSurface Create (GRContext context, GRBackendTextureDesc desc, SKSurfaceProps props)
{
return GetObject<SKSurface> (SkiaApi.sk_surface_new_backend_texture (context.Handle, ref desc, ref props));

Просмотреть файл

@ -28,9 +28,6 @@
<Compile Include="..\Tests\GlContexts\Glx\*.cs" Link="GlContexts\Glx\%(FileName)%(Extension)" />
<Compile Include="..\Tests\GlContexts\Wgl\*.cs" Link="GlContexts\Wgl\%(FileName)%(Extension)" />
</ItemGroup>
<ItemGroup>
<Compile Remove="..\Tests\SKSurfaceTest.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\Content\images\*" Link="images/%(FileName)%(Extension)">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

Просмотреть файл

@ -8,6 +8,10 @@ namespace SkiaSharp.Tests
{
private const string libGL = "/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL";
public const int GL_TEXTURE_2D = 0x0DE1;
public const int GL_UNSIGNED_BYTE = 0x1401;
public const int GL_RGBA = 0x1908;
[DllImport(libGL)]
public extern static void CGLGetVersion(out int majorvers, out int minorvers);
[DllImport(libGL)]
@ -22,5 +26,13 @@ namespace SkiaSharp.Tests
public extern static void CGLReleaseContext(IntPtr ctx);
[DllImport(libGL)]
public extern static CGLError CGLFlushDrawable(IntPtr ctx);
[DllImport(libGL)]
public static extern void glGenTextures(int n, uint[] textures);
[DllImport(libGL)]
public static extern void glDeleteTextures(int n, uint[] textures);
[DllImport(libGL)]
public static extern void glBindTexture(uint target, uint texture);
[DllImport(libGL)]
public static extern void glTexImage2D(uint target, int level, int internalformat, int width, int height, int border, uint format, uint type, IntPtr pixels);
}
}

Просмотреть файл

@ -50,5 +50,26 @@ namespace SkiaSharp.Tests
fContext = IntPtr.Zero;
}
}
public override GRGlTextureInfo CreateTexture(SKSizeI textureSize)
{
var textures = new uint[1];
Cgl.glGenTextures(textures.Length, textures);
var textureId = textures[0];
Cgl.glBindTexture(Cgl.GL_TEXTURE_2D, textureId);
Cgl.glTexImage2D(Cgl.GL_TEXTURE_2D, 0, Cgl.GL_RGBA, textureSize.Width, textureSize.Height, 0, Cgl.GL_RGBA, Cgl.GL_UNSIGNED_BYTE, IntPtr.Zero);
Cgl.glBindTexture(Cgl.GL_TEXTURE_2D, 0);
return new GRGlTextureInfo {
Id = textureId,
Target = Cgl.GL_TEXTURE_2D
};
}
public override void DestroyTexture(uint texture)
{
Cgl.glDeleteTextures(1, new[] { texture });
}
}
}

Просмотреть файл

@ -10,6 +10,8 @@ namespace SkiaSharp.Tests
public abstract void MakeCurrent();
public abstract void SwapBuffers();
public abstract void Destroy();
public abstract GRGlTextureInfo CreateTexture(SKSizeI textureSize);
public abstract void DestroyTexture(uint texture);
void IDisposable.Dispose() => Destroy();
}

Просмотреть файл

@ -8,6 +8,10 @@ namespace SkiaSharp.Tests
{
private const string libGL = "libGL";
public const int GL_TEXTURE_2D = 0x0DE1;
public const int GL_UNSIGNED_BYTE = 0x1401;
public const int GL_RGBA = 0x1908;
public const int GLX_USE_GL = 1;
public const int GLX_BUFFER_SIZE = 2;
public const int GLX_LEVEL = 3;
@ -122,5 +126,13 @@ namespace SkiaSharp.Tests
public extern static IntPtr glXCreateNewContext(IntPtr dpy, IntPtr config, int renderType, IntPtr shareList, int direct);
public static readonly glXCreateContextAttribsARBDelegate glXCreateContextAttribsARB;
public delegate IntPtr glXCreateContextAttribsARBDelegate(IntPtr dpy, IntPtr config, IntPtr share_context, int direct, int[] attrib_list);
[DllImport(libGL)]
public static extern void glGenTextures(int n, uint[] textures);
[DllImport(libGL)]
public static extern void glDeleteTextures(int n, uint[] textures);
[DllImport(libGL)]
public static extern void glBindTexture(uint target, uint texture);
[DllImport(libGL)]
public static extern void glTexImage2D(uint target, int level, int internalformat, int width, int height, int border, uint format, uint type, IntPtr pixels);
}
}

Просмотреть файл

@ -140,5 +140,26 @@ namespace SkiaSharp.Tests
fDisplay = IntPtr.Zero;
}
}
public override GRGlTextureInfo CreateTexture(SKSizeI textureSize)
{
var textures = new uint[1];
Glx.glGenTextures(textures.Length, textures);
var textureId = textures[0];
Glx.glBindTexture(Glx.GL_TEXTURE_2D, textureId);
Glx.glTexImage2D(Glx.GL_TEXTURE_2D, 0, Glx.GL_RGBA, textureSize.Width, textureSize.Height, 0, Glx.GL_RGBA, Glx.GL_UNSIGNED_BYTE, IntPtr.Zero);
Glx.glBindTexture(Glx.GL_TEXTURE_2D, 0);
return new GRGlTextureInfo {
Id = textureId,
Target = Glx.GL_TEXTURE_2D
};
}
public override void DestroyTexture(uint texture)
{
Glx.glDeleteTextures(1, new[] { texture });
}
}
}

Просмотреть файл

@ -14,6 +14,9 @@ namespace SkiaSharp.Tests
public const int GL_VERSION = 0x1F02;
public const int GL_EXTENSIONS = 0x1F03;
public const int GL_TEXTURE_2D = 0x0DE1;
public const int GL_UNSIGNED_BYTE = 0x1401;
public const int GL_RGBA = 0x1908;
public const int WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000;
public const int WGL_DRAW_TO_WINDOW_ARB = 0x2001;
@ -232,6 +235,18 @@ namespace SkiaSharp.Tests
var intPtr = glGetString(value);
return Marshal.PtrToStringAnsi(intPtr);
}
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern void glGenTextures(int n, uint[] textures);
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern void glDeleteTextures(int n, uint[] textures);
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern void glBindTexture(uint target, uint texture);
[DllImport(opengl32, CallingConvention = CallingConvention.Winapi)]
public static extern void glTexImage2D(uint target, int level, int internalformat, int width, int height, int border, uint format, uint type, IntPtr pixels);
}
[UnmanagedFunctionPointer(CallingConvention.Winapi)]

Просмотреть файл

@ -159,5 +159,27 @@ namespace SkiaSharp.Tests
User32.UnregisterClass("Griffin", Kernel32.CurrentModuleHandle);
}
public override GRGlTextureInfo CreateTexture(SKSizeI textureSize)
{
var textures = new uint[1];
Wgl.glGenTextures(textures.Length, textures);
var textureId = textures[0];
Wgl.glBindTexture(Wgl.GL_TEXTURE_2D, textureId);
Wgl.glTexImage2D(Wgl.GL_TEXTURE_2D, 0, Wgl.GL_RGBA, textureSize.Width, textureSize.Height, 0, Wgl.GL_RGBA, Wgl.GL_UNSIGNED_BYTE, IntPtr.Zero);
Wgl.glBindTexture(Wgl.GL_TEXTURE_2D, 0);
return new GRGlTextureInfo
{
Id = textureId,
Target = Wgl.GL_TEXTURE_2D
};
}
public override void DestroyTexture(uint texture)
{
Wgl.glDeleteTextures(1, new[] { texture });
}
}
}

Просмотреть файл

@ -1,44 +1,151 @@
using System;
#if NET_STANDARD
#else
#define SYSTEM_DRAWING
#endif
using System;
using Xunit;
#if SYSTEM_DRAWING
using System.Drawing;
using System.Drawing.Imaging;
using Xunit;
#endif
namespace SkiaSharp.Tests
{
public class SKSurfaceTest : SKTest, IDisposable
public class SKSurfaceTest : SKTest
{
protected const int width = 100;
protected const int height = 100;
private const int width = 100;
private const int height = 100;
protected Bitmap bitmap;
public SKSurfaceTest()
private void DrawGpuSurface(Action<SKSurface, SKImageInfo> draw)
{
bitmap = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
}
public void Dispose()
{
bitmap.Dispose();
bitmap = null;
}
private void Draw(Action<SKSurface> draw)
{
var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
using (var surface = SKSurface.Create(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul, data.Scan0, data.Stride))
using (var ctx = CreateGlContext())
{
draw(surface);
}
ctx.MakeCurrent();
bitmap.UnlockBits(data);
var info = new SKImageInfo(100, 100);
using (var grContext = GRContext.Create(GRBackend.OpenGL))
using (var surface = SKSurface.Create(grContext, true, info))
{
Assert.NotNull(surface);
draw(surface, info);
}
}
}
private void DrawGpuTexture(Action<SKSurface, GRGlBackendTextureDesc> draw)
{
using (var ctx = CreateGlContext())
{
ctx.MakeCurrent();
// create the texture
var textureInfo = ctx.CreateTexture(new SKSizeI(100, 100));
var textureDesc = new GRGlBackendTextureDesc
{
Width = 100,
Height = 100,
Config = GRPixelConfig.Rgba8888,
Flags = GRBackendTextureDescFlags.RenderTarget,
Origin = GRSurfaceOrigin.TopLeft,
SampleCount = 0,
TextureHandle = textureInfo,
};
// create the surface
using (var grContext = GRContext.Create(GRBackend.OpenGL))
using (var surface = SKSurface.CreateAsRenderTarget(grContext, textureDesc))
{
Assert.NotNull(surface);
draw(surface, textureDesc);
}
// clean up
ctx.DestroyTexture(textureInfo.Id);
}
}
[SkippableFact]
public void GpuBackendSurfaceIsCreated()
{
DrawGpuSurface((surface, info) =>
{
Assert.NotNull(surface);
var canvas = surface.Canvas;
Assert.NotNull(canvas);
canvas.Clear(SKColors.Transparent);
});
}
[SkippableFact]
public void GpuTextureSurfaceIsCreated()
{
DrawGpuTexture((surface, desc) =>
{
Assert.NotNull(surface);
var canvas = surface.Canvas;
Assert.NotNull(canvas);
canvas.Clear(SKColors.Transparent);
});
}
[SkippableFact]
public void GpuTextureSurfaceCanBeRead()
{
DrawGpuTexture((surface, desc) =>
{
var canvas = surface.Canvas;
canvas.Clear(SKColors.Red);
canvas.Flush();
using (var image = surface.Snapshot())
{
Assert.True(image.IsTextureBacked);
using (var raster = image.ToRasterImage())
{
Assert.False(raster.IsTextureBacked);
using (var bmp = SKBitmap.FromImage(raster))
{
Assert.Equal(SKColors.Red, bmp.GetPixel(0, 0));
}
}
}
});
}
#if SYSTEM_DRAWING
private void DrawBitmap(Action<SKSurface, BitmapData> draw)
{
using (var bitmap = new Bitmap(width, height, PixelFormat.Format32bppPArgb))
{
var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
using (var surface = SKSurface.Create(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul, data.Scan0, data.Stride))
{
Assert.NotNull(surface);
draw(surface, data);
}
bitmap.UnlockBits(data);
}
}
[SkippableFact]
public void SurfaceCanvasReturnTheSameInstance()
{
Draw(surface =>
DrawBitmap((surface, data) =>
{
var skcanvas1 = surface.Canvas;
var skcanvas2 = surface.Canvas;
@ -56,38 +163,18 @@ namespace SkiaSharp.Tests
[SkippableFact]
public void SecondSurfaceWasCreatedDifferent()
{
var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
DrawBitmap((surface, data) =>
{
var surface2 = SKSurface.Create(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul, data.Scan0, data.Stride);
var surface1 = SKSurface.Create(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul, data.Scan0, data.Stride);
var surface2 = SKSurface.Create(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul, data.Scan0, data.Stride);
Assert.NotNull(surface2);
Assert.NotNull(surface1);
Assert.NotNull(surface2);
Assert.NotEqual(surface, surface2);
Assert.NotEqual(surface.Handle, surface2.Handle);
Assert.NotEqual(surface1, surface2);
Assert.NotEqual(surface1.Handle, surface2.Handle);
surface1.Dispose();
surface2.Dispose();
bitmap.UnlockBits(data);
}
[SkippableFact]
public void SurfaceWasCreated()
{
var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
var surface = SKSurface.Create(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul, data.Scan0, data.Stride);
Assert.NotNull(surface);
Assert.NotEqual(IntPtr.Zero, surface.Handle);
surface.Dispose();
Assert.Equal(IntPtr.Zero, surface.Handle);
bitmap.UnlockBits(data);
surface2.Dispose();
});
}
#endif
}
}