MemoryBlock.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. using SmartCoalApplication.SystemLayer;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace SmartCoalApplication.Core
  9. {
  10. [Serializable]
  11. public unsafe sealed class MemoryBlock : IDisposable, ICloneable
  12. {
  13. private const int serializationChunkSize = 1048576;
  14. private const long largeBlockThreshold = 65536;
  15. private long length;
  16. [NonSerialized]
  17. private void* voidStar;
  18. [NonSerialized]
  19. private bool valid;
  20. private MemoryBlock parentBlock = null;
  21. [NonSerialized]
  22. private IntPtr bitmapHandle = IntPtr.Zero;
  23. private int bitmapWidth;
  24. private int bitmapHeight;
  25. private bool disposed = false;
  26. public void* VoidStar
  27. {
  28. get
  29. {
  30. if (disposed)
  31. {
  32. throw new ObjectDisposedException("MemoryBlock");
  33. }
  34. return voidStar;
  35. }
  36. }
  37. public bool MaySetAllowWrites
  38. {
  39. get
  40. {
  41. if (disposed)
  42. {
  43. throw new ObjectDisposedException("MemoryBlock");
  44. }
  45. if (this.parentBlock != null)
  46. {
  47. return this.parentBlock.MaySetAllowWrites;
  48. }
  49. else
  50. {
  51. return (this.length >= largeBlockThreshold && this.bitmapHandle != IntPtr.Zero);
  52. }
  53. }
  54. }
  55. public static void CopyBlock(MemoryBlock dst, long dstOffset, MemoryBlock src, long srcOffset, long length)
  56. {
  57. if ((dstOffset + length > dst.length) || (srcOffset + length > src.length))
  58. {
  59. throw new ArgumentOutOfRangeException("", "copy ranges were out of bounds");
  60. }
  61. if (dstOffset < 0)
  62. {
  63. throw new ArgumentOutOfRangeException("dstOffset", dstOffset, "must be >= 0");
  64. }
  65. if (srcOffset < 0)
  66. {
  67. throw new ArgumentOutOfRangeException("srcOffset", srcOffset, "must be >= 0");
  68. }
  69. if (length < 0)
  70. {
  71. throw new ArgumentOutOfRangeException("length", length, "must be >= 0");
  72. }
  73. void* dstPtr = (void*)((byte*)dst.VoidStar + dstOffset);
  74. void* srcPtr = (void*)((byte*)src.VoidStar + srcOffset);
  75. Memory.Copy(dstPtr, srcPtr, (ulong)length);
  76. }
  77. object ICloneable.Clone()
  78. {
  79. if (disposed)
  80. {
  81. throw new ObjectDisposedException("MemoryBlock");
  82. }
  83. return (object)Clone();
  84. }
  85. public MemoryBlock Clone()
  86. {
  87. if (disposed)
  88. {
  89. throw new ObjectDisposedException("MemoryBlock");
  90. }
  91. MemoryBlock dupe = new MemoryBlock(this.length);
  92. CopyBlock(dupe, 0, this, 0, length);
  93. return dupe;
  94. }
  95. public MemoryBlock(long bytes)
  96. {
  97. if (bytes <= 0)
  98. {
  99. throw new ArgumentOutOfRangeException("bytes", bytes, "Bytes must be greater than zero");
  100. }
  101. this.length = bytes;
  102. this.parentBlock = null;
  103. this.voidStar = Allocate(bytes).ToPointer();
  104. this.valid = true;
  105. }
  106. public MemoryBlock(int width, int height)
  107. {
  108. if (width < 0 && height < 0)
  109. {
  110. throw new ArgumentOutOfRangeException("width/height", new Size(width, height), "width and height must be >= 0");
  111. }
  112. else if (width < 0)
  113. {
  114. throw new ArgumentOutOfRangeException("width", width, "width must be >= 0");
  115. }
  116. else if (height < 0)
  117. {
  118. throw new ArgumentOutOfRangeException("height", width, "height must be >= 0");
  119. }
  120. this.length = width * height * ColorBgra.SizeOf;
  121. this.parentBlock = null;
  122. this.voidStar = Allocate(width, height, out this.bitmapHandle).ToPointer();
  123. this.valid = true;
  124. this.bitmapWidth = width;
  125. this.bitmapHeight = height;
  126. }
  127. public unsafe MemoryBlock(MemoryBlock parentBlock, long offset, long length)
  128. {
  129. if (offset + length > parentBlock.length)
  130. {
  131. throw new ArgumentOutOfRangeException();
  132. }
  133. this.parentBlock = parentBlock;
  134. byte* bytePointer = (byte*)parentBlock.VoidStar;
  135. bytePointer += offset;
  136. this.voidStar = (void*)bytePointer;
  137. this.valid = true;
  138. this.length = length;
  139. }
  140. ~MemoryBlock()
  141. {
  142. Dispose(false);
  143. }
  144. public void Dispose()
  145. {
  146. Dispose(true);
  147. GC.SuppressFinalize(this);
  148. }
  149. private void Dispose(bool disposing)
  150. {
  151. if (!disposed)
  152. {
  153. disposed = true;
  154. if (disposing)
  155. {
  156. }
  157. if (this.valid && parentBlock == null)
  158. {
  159. if (this.bitmapHandle != IntPtr.Zero)
  160. {
  161. Memory.FreeBitmap(this.bitmapHandle, this.bitmapWidth, this.bitmapHeight);
  162. }
  163. else if (this.length >= largeBlockThreshold)
  164. {
  165. Memory.FreeLarge(new IntPtr(voidStar), (ulong)this.length);
  166. }
  167. else
  168. {
  169. Memory.Free(new IntPtr(voidStar));
  170. }
  171. }
  172. parentBlock = null;
  173. voidStar = null;
  174. this.valid = false;
  175. }
  176. }
  177. private static IntPtr Allocate(int width, int height, out IntPtr handle)
  178. {
  179. return Allocate(width, height, out handle, true);
  180. }
  181. private static IntPtr Allocate(int width, int height, out IntPtr handle, bool allowRetry)
  182. {
  183. IntPtr block;
  184. try
  185. {
  186. block = Memory.AllocateBitmap(width, height, out handle);
  187. }
  188. catch (OutOfMemoryException)
  189. {
  190. if (allowRetry)
  191. {
  192. Utility.GCFullCollect();
  193. return Allocate(width, height, out handle, false);
  194. }
  195. else
  196. {
  197. throw;
  198. }
  199. }
  200. return block;
  201. }
  202. private static IntPtr Allocate(long bytes)
  203. {
  204. return Allocate(bytes, true);
  205. }
  206. private static IntPtr Allocate(long bytes, bool allowRetry)
  207. {
  208. IntPtr block;
  209. try
  210. {
  211. if (bytes >= largeBlockThreshold)
  212. {
  213. block = Memory.AllocateLarge((ulong)bytes);
  214. }
  215. else
  216. {
  217. block = Memory.Allocate((ulong)bytes);
  218. }
  219. }
  220. catch (OutOfMemoryException)
  221. {
  222. if (allowRetry)
  223. {
  224. Utility.GCFullCollect();
  225. return Allocate(bytes, false);
  226. }
  227. else
  228. {
  229. throw;
  230. }
  231. }
  232. return block;
  233. }
  234. }
  235. }