Skip to content

Commit

Permalink
Improve perfromance for loading from Stream on Windows (dotnet/corefx…
Browse files Browse the repository at this point in the history
…#31142)

* Improve perfromance for loading from Stream on Windows

- Make IStream blittable and move to Interop
- Change GPStream to use Span APIs
- Make STATSTG blittable and move to Interop
- Fill out corners correctly in GPStream
- Remove extra allocations opening Gifs
- Fix allocations in FrameDimensionsList and move to shared
- Move IPicture to Icon.Windows (was Windows specific and used IStream, needs cleanup and moving to Interop)
- Add perf tests for opening images

* Add netcoreapp2.0 variant

* Fall back to heap for large frame counts

* Add netcoreapp2.0 to packages.

* Fix issue in GpStream and add test
Undo netcoreapp2.1 change


Commit migrated from dotnet/corefx@dee4344
  • Loading branch information
JeremyKuhne committed Jul 20, 2018
1 parent ddb5b5e commit 1365275
Show file tree
Hide file tree
Showing 21 changed files with 788 additions and 631 deletions.
22 changes: 22 additions & 0 deletions src/libraries/Common/src/Interop/Windows/Interop.HRESULT.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

internal static partial class Interop
{
// https://msdn.microsoft.com/en-us/library/cc231198.aspx
internal enum HRESULT : int
{
S_OK = 0,
S_FALSE = 1,
E_NOTIMPL = unchecked((int)0x80004001),
E_ABORT = unchecked((int)0x80004004),
E_FAIL = unchecked((int)0x80004005),
E_UNEXPECTED = unchecked((int)0x8000FFFF),
STG_E_INVALIDFUNCTION = unchecked((int)0x80030001L),
STG_E_INVALIDPARAMETER = unchecked((int)0x80030057),
STG_E_INVALIDFLAG = unchecked((int)0x800300FF),
E_ACCESSDENIED = unchecked((int)0x80070005),
E_INVALIDARG = unchecked((int)0x80070057),
}
}
67 changes: 67 additions & 0 deletions src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.IO;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Ole32
{
/// <summary>
/// COM IStream interface. <see cref="https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-istream"/>
/// </summary>
/// <remarks>
/// The definition in <see cref="System.Runtime.InteropServices.ComTypes"/> does not lend
/// itself to efficiently accessing / implementing IStream.
/// </remarks>
[ComImport,
Guid("0000000C-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal unsafe interface IStream
{
// pcbRead is optional so it must be a pointer
void Read(byte* pv, uint cb, uint* pcbRead);

// pcbWritten is optional so it must be a pointer
void Write(byte* pv, uint cb, uint* pcbWritten);

// SeekOrgin matches the native values, plibNewPosition is optional
void Seek(long dlibMove, SeekOrigin dwOrigin, ulong* plibNewPosition);

void SetSize(ulong libNewSize);

// pcbRead and pcbWritten are optional
void CopyTo(
IStream pstm,
ulong cb,
ulong* pcbRead,
ulong* pcbWritten);

void Commit(uint grfCommitFlags);

void Revert();

// Using PreserveSig to allow explicitly returning the HRESULT for "not supported".

[PreserveSig]
HRESULT LockRegion(
ulong libOffset,
ulong cb,
uint dwLockType);

[PreserveSig]
HRESULT UnlockRegion(
ulong libOffset,
ulong cb,
uint dwLockType);

void Stat(
out STATSTG pstatstg,
STATFLAG grfStatFlag);

IStream Clone();
}
}
}
26 changes: 26 additions & 0 deletions src/libraries/Common/src/Interop/Windows/Ole32/Interop.STATFLAG.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

internal static partial class Interop
{
internal static partial class Ole32
{
/// <summary>
/// Stat flags for <see cref="IStream.Stat(out STATSTG, STATFLAG)"/>.
/// <see cref="https://docs.microsoft.com/en-us/windows/desktop/api/wtypes/ne-wtypes-tagstatflag"/>
/// </summary>
internal enum STATFLAG : uint
{
/// <summary>
/// Stat includes the name.
/// </summary>
STATFLAG_DEFAULT = 0,

/// <summary>
/// Stat doesn't include the name.
/// </summary>
STATFLAG_NONAME = 1
}
}
}
85 changes: 85 additions & 0 deletions src/libraries/Common/src/Interop/Windows/Ole32/Interop.STATSTG.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

internal static partial class Interop
{
internal static partial class Ole32
{
/// <summary>
/// Statistics for <see cref="IStream"/>.
/// <see cref="https://docs.microsoft.com/en-us/windows/desktop/api/objidl/ns-objidl-tagstatstg"/>
/// </summary>
/// <remarks>
/// The definition in <see cref="System.Runtime.InteropServices.ComTypes"/> isn't blittable.
/// </remarks>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct STATSTG
{
/// <summary>
/// Pointer to the name.
/// </summary>
private IntPtr pwcsName;
public STGTY type;

/// <summary>
/// Size of the stream in bytes.
/// </summary>
public ulong cbSize;

public FILETIME mtime;
public FILETIME ctime;
public FILETIME atime;

/// <summary>
/// The stream mode.
/// </summary>
public STGM grfMode;

/// <summary>
/// Supported locking modes.
/// <see cref="https://docs.microsoft.com/en-us/windows/desktop/api/objidl/ne-objidl-taglocktype"/>
/// </summary>
/// <remarks>
/// '0' means does not support lock modes.
/// </remarks>
public uint grfLocksSupported;

/// <remarks>
/// Only for IStorage objects
/// </remarks>
public Guid clsid;

/// <remarks>
/// Only valid for IStorage objects.
/// </remarks>
public uint grfStateBits;
public uint reserved;

public string GetName() => Marshal.PtrToStringUni(pwcsName);

/// <summary>
/// Caller is responsible for freeing the name memory.
/// </summary>
public void FreeName()
{
if (pwcsName != IntPtr.Zero)
Marshal.FreeCoTaskMem(pwcsName);

pwcsName = IntPtr.Zero;
}

/// <summary>
/// Callee is repsonsible for allocating the name memory.
/// </summary>
public void AllocName(string name)
{
pwcsName = Marshal.StringToCoTaskMemUni(name);
}
}
}
}
42 changes: 42 additions & 0 deletions src/libraries/Common/src/Interop/Windows/Ole32/Interop.STGM.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;

internal static partial class Interop
{
internal static partial class Ole32
{
/// <summary>
/// Stream / storage modes.
/// <see cref="https://docs.microsoft.com/en-us/windows/desktop/Stg/stgm-constants"/>
/// </summary>
[Flags]
internal enum STGM : uint
{
/// <summary>
/// Read only, and each change to a storage or stream element is written as it occurs.
/// Fails if the given storage object already exists.
/// [STGM_DIRECT] [STGM_READ] [STGM_FAILIFTHERE] [STGM_SHARE_DENY_WRITE]
/// </summary>
Default = 0x00000000,

STGM_TRANSACTED = 0x00010000,
STGM_SIMPLE = 0x08000000,
STGM_WRITE = 0x00000001,
STGM_READWRITE = 0x00000002,
STGM_SHARE_DENY_NONE = 0x00000040,
STGM_SHARE_DENY_READ = 0x00000030,
STGM_SHARE_DENY_WRITE = 0x00000020,
STGM_SHARE_EXCLUSIVE = 0x00000010,
STGM_PRIORITY = 0x00040000,
STGM_DELETEONRELEASE = 0x04000000,
STGM_NOSCRATCH = 0x00100000,
STGM_CREATE = 0x00001000,
STGM_CONVERT = 0x00020000,
STGM_NOSNAPSHOT = 0x00200000,
STGM_DIRECT_SWMR = 0x00400000
}
}
}
21 changes: 21 additions & 0 deletions src/libraries/Common/src/Interop/Windows/Ole32/Interop.STGTY.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

internal static partial class Interop
{
internal static partial class Ole32
{
/// <summary>
/// Type of the storage element. Used with <see cref="STATSTG"/>.
/// <see cref="https://docs.microsoft.com/en-us/windows/desktop/api/objidl/ne-objidl-tagstgty"/>
/// </summary>
internal enum STGTY : uint
{
STGTY_STORAGE = 1,
STGTY_STREAM = 2,
STGTY_LOCKBYTES = 3,
STGTY_PROPERTY = 4
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<ProjectGuid>{191B3618-FECD-4ABD-9D6B-5AC90DC33621}</ProjectGuid>
Expand Down Expand Up @@ -276,6 +276,24 @@
<Compile Include="$(CommonPath)\System\Runtime\InteropServices\FunctionWrapper.Windows.cs">
<Link>Common\System\Runtime\InteropServices\FunctionWrapper.Windows.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Ole32\Interop.IStream.cs">
<Link>Common\Interop\Windows\Ole32\Interop.IStream.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Ole32\Interop.STATSTG.cs">
<Link>Common\Interop\Windows\Ole32\Interop.STATSTG.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Ole32\Interop.STGTY.cs">
<Link>Common\Interop\Windows\Ole32\Interop.STGTY.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Ole32\Interop.STATFLAG.cs">
<Link>Common\Interop\Windows\Ole32\Interop.STATFLAG.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Ole32\Interop.STGM.cs">
<Link>Common\Interop\Windows\Ole32\Interop.STGM.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Interop.HRESULT.cs">
<Link>Common\Interop\Windows\Interop.HRESULT.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="$(TargetGroup.StartsWith('netcoreapp')) AND '$(TargetsUnix)' == 'true'">
<!-- Unix-specific -->
Expand Down Expand Up @@ -339,6 +357,7 @@
<ItemGroup Condition="'$(TargetsNetFx)' != 'true'">
<Reference Include="Microsoft.Win32.Primitives" />
<Reference Condition="'$(TargetsWindows)' == 'true'" Include="Microsoft.Win32.SystemEvents" />
<Reference Include="System.Buffers" />
<Reference Include="System.Collections" />
<Reference Include="System.Collections.NonGeneric" />
<Reference Include="System.Collections.Specialized" />
Expand All @@ -348,6 +367,7 @@
<Reference Include="System.Diagnostics.TraceSource" />
<Reference Include="System.Drawing.Primitives" />
<Reference Include="System.IO.FileSystem" />
<Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
Expand Down
Loading

0 comments on commit 1365275

Please sign in to comment.