123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- using SmartCoalApplication.SystemLayer;
- using System;
- using System.Collections.Generic;
- using System.Drawing;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace SmartCoalApplication.Core
- {
- [Serializable]
- public unsafe sealed class MemoryBlock : IDisposable, ICloneable
- {
- private const int serializationChunkSize = 1048576;
- private const long largeBlockThreshold = 65536;
- private long length;
- [NonSerialized]
- private void* voidStar;
- [NonSerialized]
- private bool valid;
- private MemoryBlock parentBlock = null;
- [NonSerialized]
- private IntPtr bitmapHandle = IntPtr.Zero;
- private int bitmapWidth;
- private int bitmapHeight;
- private bool disposed = false;
- public void* VoidStar
- {
- get
- {
- if (disposed)
- {
- throw new ObjectDisposedException("MemoryBlock");
- }
- return voidStar;
- }
- }
- public bool MaySetAllowWrites
- {
- get
- {
- if (disposed)
- {
- throw new ObjectDisposedException("MemoryBlock");
- }
- if (this.parentBlock != null)
- {
- return this.parentBlock.MaySetAllowWrites;
- }
- else
- {
- return (this.length >= largeBlockThreshold && this.bitmapHandle != IntPtr.Zero);
- }
- }
- }
- public static void CopyBlock(MemoryBlock dst, long dstOffset, MemoryBlock src, long srcOffset, long length)
- {
- if ((dstOffset + length > dst.length) || (srcOffset + length > src.length))
- {
- throw new ArgumentOutOfRangeException("", "copy ranges were out of bounds");
- }
- if (dstOffset < 0)
- {
- throw new ArgumentOutOfRangeException("dstOffset", dstOffset, "must be >= 0");
- }
- if (srcOffset < 0)
- {
- throw new ArgumentOutOfRangeException("srcOffset", srcOffset, "must be >= 0");
- }
- if (length < 0)
- {
- throw new ArgumentOutOfRangeException("length", length, "must be >= 0");
- }
- void* dstPtr = (void*)((byte*)dst.VoidStar + dstOffset);
- void* srcPtr = (void*)((byte*)src.VoidStar + srcOffset);
- Memory.Copy(dstPtr, srcPtr, (ulong)length);
- }
- object ICloneable.Clone()
- {
- if (disposed)
- {
- throw new ObjectDisposedException("MemoryBlock");
- }
- return (object)Clone();
- }
- public MemoryBlock Clone()
- {
- if (disposed)
- {
- throw new ObjectDisposedException("MemoryBlock");
- }
- MemoryBlock dupe = new MemoryBlock(this.length);
- CopyBlock(dupe, 0, this, 0, length);
- return dupe;
- }
- public MemoryBlock(long bytes)
- {
- if (bytes <= 0)
- {
- throw new ArgumentOutOfRangeException("bytes", bytes, "Bytes must be greater than zero");
- }
- this.length = bytes;
- this.parentBlock = null;
- this.voidStar = Allocate(bytes).ToPointer();
- this.valid = true;
- }
- public MemoryBlock(int width, int height)
- {
- if (width < 0 && height < 0)
- {
- throw new ArgumentOutOfRangeException("width/height", new Size(width, height), "width and height must be >= 0");
- }
- else if (width < 0)
- {
- throw new ArgumentOutOfRangeException("width", width, "width must be >= 0");
- }
- else if (height < 0)
- {
- throw new ArgumentOutOfRangeException("height", width, "height must be >= 0");
- }
- this.length = width * height * ColorBgra.SizeOf;
- this.parentBlock = null;
- this.voidStar = Allocate(width, height, out this.bitmapHandle).ToPointer();
- this.valid = true;
- this.bitmapWidth = width;
- this.bitmapHeight = height;
- }
- public unsafe MemoryBlock(MemoryBlock parentBlock, long offset, long length)
- {
- if (offset + length > parentBlock.length)
- {
- throw new ArgumentOutOfRangeException();
- }
- this.parentBlock = parentBlock;
- byte* bytePointer = (byte*)parentBlock.VoidStar;
- bytePointer += offset;
- this.voidStar = (void*)bytePointer;
- this.valid = true;
- this.length = length;
- }
- ~MemoryBlock()
- {
- Dispose(false);
- }
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- private void Dispose(bool disposing)
- {
- if (!disposed)
- {
- disposed = true;
- if (disposing)
- {
- }
- if (this.valid && parentBlock == null)
- {
- if (this.bitmapHandle != IntPtr.Zero)
- {
- Memory.FreeBitmap(this.bitmapHandle, this.bitmapWidth, this.bitmapHeight);
- }
- else if (this.length >= largeBlockThreshold)
- {
- Memory.FreeLarge(new IntPtr(voidStar), (ulong)this.length);
- }
- else
- {
- Memory.Free(new IntPtr(voidStar));
- }
- }
- parentBlock = null;
- voidStar = null;
- this.valid = false;
- }
- }
- private static IntPtr Allocate(int width, int height, out IntPtr handle)
- {
- return Allocate(width, height, out handle, true);
- }
- private static IntPtr Allocate(int width, int height, out IntPtr handle, bool allowRetry)
- {
- IntPtr block;
- try
- {
- block = Memory.AllocateBitmap(width, height, out handle);
- }
- catch (OutOfMemoryException)
- {
- if (allowRetry)
- {
- Utility.GCFullCollect();
- return Allocate(width, height, out handle, false);
- }
- else
- {
- throw;
- }
- }
- return block;
- }
- private static IntPtr Allocate(long bytes)
- {
- return Allocate(bytes, true);
- }
- private static IntPtr Allocate(long bytes, bool allowRetry)
- {
- IntPtr block;
- try
- {
- if (bytes >= largeBlockThreshold)
- {
- block = Memory.AllocateLarge((ulong)bytes);
- }
- else
- {
- block = Memory.Allocate((ulong)bytes);
- }
- }
- catch (OutOfMemoryException)
- {
- if (allowRetry)
- {
- Utility.GCFullCollect();
- return Allocate(bytes, false);
- }
- else
- {
- throw;
- }
- }
- return block;
- }
- }
- }
|