private bool valid; // if voidStar is null, and this is false, we know that it's null because allocation failed. otherwise we have a real error #endregion Fields #region Constructors /// <summary> /// Creates a new MemoryBlock instance and allocates the requested number of bytes. /// </summary> /// <param name="bytes"></param> 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; }
/// <summary> /// Creates a new instance of the Surface class. /// </summary> /// <param name="width">The width, in pixels, of the new Surface.</param> /// <param name="height">The height, in pixels, of the new Surface.</param> public Surface(int width, int height) { int stride; long bytes; try { stride = checked(width * ColorBgra.SizeOf); bytes = (long)height * (long)stride; } catch (OverflowException ex) { throw new OutOfMemoryException("Dimensions are too large - not enough memory, width=" + width.ToString() + ", height=" + height.ToString(), ex); } MemoryBlock scan0 = new MemoryBlock(width, height); Create(width, height, stride, scan0); }
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; }
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; Memory.Free((IntPtr)voidStar); voidStar = null; this.valid = false; } }
/// <summary> /// Creates a new parent MemoryBlock and copies our contents into it /// </summary> public MemoryBlock Clone() { if (disposed) { throw new ObjectDisposedException("MemoryBlock"); } MemoryBlock dupe = new MemoryBlock(this.length); CopyBlock(dupe, 0, this, 0, length); return dupe; }
/// <summary> /// Copies bytes from one area of memory to another. Since this function works /// with MemoryBlock instances, it does bounds checking. /// </summary> /// <param name="dst">The MemoryBlock to copy bytes to.</param> /// <param name="dstOffset">The offset within dst to copy bytes to.</param> /// <param name="src">The MemoryBlock to copy bytes from.</param> /// <param name="srcOffset">The offset within src to copy bytes from.</param> /// <param name="length">The number of bytes to copy.</param> 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); }
/// <summary> /// Creates a new MemoryBlock instance that refers to part of another MemoryBlock. /// The other MemoryBlock is the parent, and this new instance is the child. /// </summary> 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; }
private void ExpandUncompressedLine(MemoryBlock dst, int dstIndex, ref TgaHeader header, Stream input, int width, int y, int xoffset, ColorBgra[] palette) { for (int i = 0; i < width; ++i) { ColorBgra color = ReadColor(input, header.pixelDepth, palette); dst[dstIndex] = color[0]; dst[1 + dstIndex] = color[1]; dst[2 + dstIndex] = color[2]; dst[3 + dstIndex] = color[3]; dstIndex += 4; } }
private byte ExpandCompressedLine(MemoryBlock dst, int dstIndex, ref TgaHeader header, Stream input, int width, int y, byte rleLeftOver, ColorBgra[] palette) { byte rle; long filePos = 0; int x = 0; while (x < width) { if (rleLeftOver != 255) { rle = rleLeftOver; rleLeftOver = 255; } else { int byte1 = input.ReadByte(); if (byte1 == -1) { throw new EndOfStreamException(); } else { rle = (byte)byte1; } } if ((rle & 128) != 0) { // RLE Encoded packet rle -= 127; // calculate real repeat count if ((x + rle) > width) { rleLeftOver = (byte)(128 + (rle - (width - x) - 1)); filePos = input.Position; rle = (byte)(width - x); } ColorBgra color = ReadColor(input, header.pixelDepth, palette); for (int ix = 0; ix < rle; ++ix) { int index = dstIndex + (ix * ColorBgra.SizeOf); dst[index] = color[0]; dst[1 + index] = color[1]; dst[2 + index] = color[2]; dst[3 + index] = color[3]; } if (rleLeftOver != 255) { input.Position = filePos; } } else { // Raw packet rle += 1; // calculate real repeat count if ((x + rle) > width) { rleLeftOver = (byte)(rle - (width - x) - 1); rle = (byte)(width - x); } ExpandUncompressedLine(dst, dstIndex, ref header, input, rle, y, x, palette); } dstIndex += rle * ColorBgra.SizeOf; x += rle; } return rleLeftOver; }
private MemoryBlock(SerializationInfo info, StreamingContext context) { disposed = false; // Try to read a 64-bit value, and for backwards compatibility fall back on a 32-bit value. try { this.length = info.GetInt64("length64"); } catch (SerializationException) { this.length = (long)info.GetInt32("length"); } try { this.bitmapWidth = (int)info.GetInt32("bitmapWidth"); this.bitmapHeight = (int)info.GetInt32("bitmapHeight"); if (this.bitmapWidth != 0 || this.bitmapHeight != 0) { long bytes = (long)this.bitmapWidth * (long)this.bitmapHeight * (long)ColorBgra.SizeOf; if (bytes != this.length) { throw new ApplicationException("Invalid file format: width * height * 4 != length"); } } } catch (SerializationException) { this.bitmapWidth = 0; this.bitmapHeight = 0; } bool hasParent = info.GetBoolean("hasParent"); if (hasParent) { this.parentBlock = (MemoryBlock)info.GetValue("parentBlock", typeof(MemoryBlock)); // Try to read a 64-bit value, and for backwards compatibility fall back on a 32-bit value. long parentOffset; try { parentOffset = info.GetInt64("parentOffset64"); } catch (SerializationException) { parentOffset = (long)info.GetInt32("parentOffset"); } this.voidStar = (void *)((byte *)parentBlock.VoidStar + parentOffset); this.valid = true; } else { DeferredFormatter deferredFormatter = context.Context as DeferredFormatter; bool deferred = false; // Was this stream serialized with deferment? foreach (SerializationEntry entry in info) { if (entry.Name == "deferred") { deferred = (bool)entry.Value; break; } } if (deferred && deferredFormatter != null) { // The newest PDN files use deferred deserialization. This lets us read straight from the stream, // minimizing memory use and adding the potential for multithreading // Deserialization will complete in IDeferredDeserializer.FinishDeserialization() deferredFormatter.AddDeferredObject(this, this.length); } else if (deferred && deferredFormatter == null) { throw new InvalidOperationException("stream has deferred serialization streams, but a DeferredFormatter was not provided"); } else { this.voidStar = Allocate(this.length).ToPointer(); this.valid = true; // Non-deferred format serializes one big byte[] chunk. This is also // how PDN files were saved with v2.1 Beta 2 and before. byte[] array = (byte[])info.GetValue("pointerData", typeof(byte[])); fixed (byte *pbArray = array) { Memory.Copy(this.VoidStar, (void *)pbArray, (ulong)array.LongLength); } } } }
/// <summary> /// Creates a new instance of the Surface class that reuses a block of memory that was previously allocated. /// </summary> /// <param name="width">The width, in pixels, for the Surface.</param> /// <param name="height">The height, in pixels, for the Surface.</param> /// <param name="stride">The stride, in bytes, for the Surface.</param> /// <param name="scan0">The MemoryBlock to use. The beginning of this buffer defines the upper left (0, 0) pixel of the Surface.</param> private Surface(int width, int height, int stride, MemoryBlock scan0) { Create(width, height, stride, scan0); }
private MemoryBlock GetRootMemoryBlock(MemoryBlock block) { MemoryBlock p = block; while (p.Parent != null) { p = p.Parent; } return p; }
private void Dispose(bool disposing) { if (!disposed) { disposed = true; if (disposing) { scan0.Dispose(); scan0 = null; } } }
private void Create(int width, int height, int stride, MemoryBlock scan0) { this.width = width; this.height = height; this.stride = stride; this.scan0 = scan0; }
public Surface CreateWindow(int x, int y, int windowWidth, int windowHeight) { if (disposed) { throw new ObjectDisposedException("Surface"); } if (windowHeight == 0) { throw new ArgumentOutOfRangeException("windowHeight", "must be greater than zero"); } Rectangle original = this.Bounds; Rectangle sub = new Rectangle(x, y, windowWidth, windowHeight); Rectangle clipped = Rectangle.Intersect(original, sub); if (clipped != sub) { throw new ArgumentOutOfRangeException("bounds", new Rectangle(x, y, windowWidth, windowHeight), "bounds parameters must be a subset of this Surface's bounds"); } long offset = ((long)stride * (long)y) + ((long)ColorBgra.SizeOf * (long)x); long length = ((windowHeight - 1) * (long)stride) + (long)windowWidth * (long)ColorBgra.SizeOf; MemoryBlock block = new MemoryBlock(this.scan0, offset, length); return new Surface(windowWidth, windowHeight, this.stride, block); }
private MemoryBlock(SerializationInfo info, StreamingContext context) { disposed = false; // Try to read a 64-bit value, and for backwards compatibility fall back on a 32-bit value. try { this.length = info.GetInt64("length64"); } catch (SerializationException) { this.length = (long)info.GetInt32("length"); } try { this.bitmapWidth = (int)info.GetInt32("bitmapWidth"); this.bitmapHeight = (int)info.GetInt32("bitmapHeight"); if (this.bitmapWidth != 0 || this.bitmapHeight != 0) { long bytes = (long)this.bitmapWidth * (long)this.bitmapHeight * (long)ColorBgra.SizeOf; if (bytes != this.length) { throw new ApplicationException("Invalid file format: width * height * 4 != length"); } } } catch (SerializationException) { this.bitmapWidth = 0; this.bitmapHeight = 0; } bool hasParent = info.GetBoolean("hasParent"); if (hasParent) { this.parentBlock = (MemoryBlock)info.GetValue("parentBlock", typeof(MemoryBlock)); // Try to read a 64-bit value, and for backwards compatibility fall back on a 32-bit value. long parentOffset; try { parentOffset = info.GetInt64("parentOffset64"); } catch (SerializationException) { parentOffset = (long)info.GetInt32("parentOffset"); } this.voidStar = (void *)((byte *)parentBlock.VoidStar + parentOffset); this.valid = true; } else { DeferredFormatter deferredFormatter = context.Context as DeferredFormatter; bool deferred = false; // Was this stream serialized with deferment? foreach (SerializationEntry entry in info) { if (entry.Name == "deferred") { deferred = (bool)entry.Value; break; } } if (deferred && deferredFormatter != null) { // The newest PDN files use deferred deserialization. This lets us read straight from the stream, // minimizing memory use and adding the potential for multithreading // Deserialization will complete in IDeferredDeserializer.FinishDeserialization() deferredFormatter.AddDeferredObject(this, this.length); } else if (deferred && deferredFormatter == null) { throw new InvalidOperationException("stream has deferred serialization streams, but a DeferredFormatter was not provided"); } else { this.voidStar = Allocate(this.length).ToPointer(); this.valid = true; // Non-deferred format serializes one big byte[] chunk. This is also // how PDN files were saved with v2.1 Beta 2 and before. byte[] array = (byte[])info.GetValue("pointerData", typeof(byte[])); fixed(byte *pbArray = array) { Memory.Copy(this.VoidStar, (void *)pbArray, (ulong)array.LongLength); } } } }