/// <summary> /// Define the fake GPU buffer (when GL_ARB_vertex_array_object is not supported) using the current client buffer. /// </summary> protected virtual void UploadClientBuffer() { if (_MemoryBufferAutoDispose == false) { // Note: client buffer is expected to be allocated and modificable; even while the GPU is rendering // using the simulated GPU buffer. We need to copy: in this way it is implemented the double buffer // mechanism of the GL_ARB_vertex_buffer_object extension // Allocate a new GPU buffer _GpuBuffer = new AlignedMemoryBuffer(ClientBufferSize, MinimumBufferAlignment); // Copy from client buffer Memory.MemoryCopy(_GpuBuffer.AlignedBuffer, ClientBufferAddress, ClientBufferSize); } else { // Note: since client buffer need to be disposed (ending set to null), we do not copy // client buffer to GPU buffer; instead, switch references and do not dispose the client buffer // Allocate GPU buffer _GpuBuffer = _ClientBuffer; // Do not need disposition (not really sure, but apart ClientBufferAddress, no reference of _ClientBuffer // should be out of here _ClientBuffer = null; } }
/// <summary> /// Allocate a new client buffer for this BufferObject. /// </summary> /// <param name="size"> /// A <see cref="UInt32"/> that determine the size of the buffer object client buffer, in bytes. /// </param> protected virtual void AllocateClientBuffer(uint size) { // Discard previous buffer ReleaseClientBuffer(); // Allocate memory, if required _ClientBuffer = new AlignedMemoryBuffer(size, MinimumBufferAlignment); }
/// <summary> /// Copy data from another AlignedMemoryBuffer. /// </summary> /// <param name="otherMemoryBuffer"> /// A <see cref="AlignedMemoryBuffer"/> which has allocated the data to be copied. /// </param> /// <param name="otherOffset"> /// A <see cref="UInt64"/> which specify an additional offset (in bytes) to apply to <paramref name="otherMemoryBuffer"/>. /// </param> /// <param name="thisOffset"> /// A <see cref="UInt64"/> which specify an additional offset (in bytes) to apply to this AlignedMemoryBuffer. /// </param> /// <param name="bytesCopied"> /// A <see cref="UInt64"/> which specify the number of bytes to be copied. /// </param> public void CopyBuffer(AlignedMemoryBuffer otherMemoryBuffer, ulong otherOffset, ulong thisOffset, ulong bytesCopied) { if (IsDisposed) { throw new ObjectDisposedException("AlignedMemoryBuffer"); } if (otherMemoryBuffer == null) { throw new ArgumentNullException("otherMemoryBuffer"); } if (otherMemoryBuffer._UnmanagedBuffer == IntPtr.Zero) { throw new ArgumentException("disposed", "otherMemoryBuffer"); } if (thisOffset + bytesCopied >= otherMemoryBuffer.Size - otherOffset) { throw new InvalidOperationException("copying out of bounds"); } if (bytesCopied > 0) { IntPtr src = new IntPtr(otherMemoryBuffer.AlignedBuffer.ToInt64() + (long)otherOffset); IntPtr dst = new IntPtr(AlignedBuffer.ToInt64() + (long)thisOffset); Memory.MemoryCopy(dst, src, bytesCopied); } }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting managed/unmanaged resources. /// </summary> /// <param name="disposing"> /// </param> protected override void Dispose(bool disposing) { if (disposing) { if (_PixelBuffers != null) { // Release the buffer buffer _PixelBuffers.Dispose(); _PixelBuffers = null; } } }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting managed/unmanaged resources. /// </summary> /// <exception cref="InvalidOperationException"> /// Exception thrown in the case <see cref="GraphicsResource.RefCount"/> is greater than zero. This means that the method is trying to dispose /// an object that is actually referenced by something else. /// </exception> protected override void Dispose(bool disposing) { // Base implementation base.Dispose(disposing); if (disposing == true) { // Simulated GPU buffer is disposed at disposition if (_GpuBuffer != null) { _GpuBuffer.Dispose(); _GpuBuffer = null; // Reset GPU buffer size _GpuBufferSize = 0; } // Release client buffer ReleaseClientBuffer(); } }
/// <summary> /// Actually create this BufferObject resources. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> used for allocating resources. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="ctx"/> is null. /// </exception> /// <exception cref="ArgumentException"> /// Exception thrown if <paramref name="ctx"/> is not current on the calling thread. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if this BufferObject has not client memory allocated and the hint is different from /// <see cref="BufferObjectHint.StaticCpuDraw"/> or <see cref="BufferObjectHint.DynamicCpuDraw"/>. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if this BufferObject is currently mapped. /// </exception> protected override void CreateObject(GraphicsContext ctx) { CheckCurrentContext(ctx); if ((ClientBufferAddress == IntPtr.Zero) && ((Hint != BufferObjectHint.StaticCpuDraw) && (Hint != BufferObjectHint.DynamicCpuDraw))) { throw new InvalidOperationException("no client buffer"); } // Determine the client buffer size uint clientBufferSize = _ClientBufferSize; if (ClientBufferAddress != IntPtr.Zero) { clientBufferSize = ClientBufferSize; } Debug.Assert(clientBufferSize > 0); // Buffer must be bound Bind(ctx); if (ctx.Caps.GlExtensions.VertexBufferObject_ARB) { if (IsMapped) { throw new InvalidOperationException("mapped"); } // Define buffer object (type, size and hints) Gl.BufferData((int)BufferType, clientBufferSize, null, (int)Hint); // Store GPU buffer size _GpuBufferSize = clientBufferSize; // Define buffer object contents if (ClientBufferAddress != IntPtr.Zero) { // Provide buffer contents Gl.BufferSubData(BufferType, IntPtr.Zero, _GpuBufferSize, ClientBufferAddress); // Release memory, if it is not required anymore if (_MemoryBufferAutoDispose) { ReleaseClientBuffer(); } } } else { // Discard previous GPU buffer, if any if (_GpuBuffer != null) { _GpuBuffer.Dispose(); } if (ClientBufferAddress == IntPtr.Zero) { // Note: GPU buffer size specified by _ClientBufferSize Debug.Assert(_ClientBufferSize > 0); // Allocate simulated GPU buffer _GpuBuffer = new AlignedMemoryBuffer(_ClientBufferSize, MinimumBufferAlignment); } else { // Let a virtual implementation decide how pass information from the client buffer and the "GPU" buffer UploadClientBuffer(); } // Store GPU buffer size _GpuBufferSize = _GpuBuffer.Size; } // Reset requested client buffer size _ClientBufferSize = 0; }
/// <summary> /// Allocate pixel data for this Image. /// </summary> /// <param name="format"> /// A <see cref="PixelLayout"/> indicating the image pixel format. /// </param> /// <param name="w"> /// A <see cref="Int32"/> indicating the image width, in pixels. /// </param> /// <param name="h"> /// A <see cref="Int32"/> indicating the image height, in pixels. /// </param> public void Create(PixelLayout format, uint w, uint h) { PixelLayoutInfo formatInfo = Pixel.GetPixelFormat(format); switch (format) { // Single plane formats case PixelLayout.GRAY8: case PixelLayout.GRAY16: case PixelLayout.GRAYF: case PixelLayout.GRAYHF: case PixelLayout.GRAYAF: case PixelLayout.RGB8: case PixelLayout.RGB15: case PixelLayout.RGB16: case PixelLayout.RGB24: case PixelLayout.RGB48: case PixelLayout.RGBF: case PixelLayout.RGBHF: case PixelLayout.RGBD: case PixelLayout.SRGB24: case PixelLayout.SBGR24: case PixelLayout.RGB30A2: case PixelLayout.RGBA32: case PixelLayout.RGBA64: case PixelLayout.RGBAF: case PixelLayout.RGBAHF: case PixelLayout.BGR8: case PixelLayout.BGR15: case PixelLayout.BGR16: case PixelLayout.BGR24: case PixelLayout.BGR48: case PixelLayout.BGRF: case PixelLayout.BGRHF: case PixelLayout.BGR30A2: case PixelLayout.BGRA32: case PixelLayout.BGRA64: case PixelLayout.BGRAF: case PixelLayout.BGRAHF: case PixelLayout.CMY24: case PixelLayout.CMYK32: case PixelLayout.CMYK64: case PixelLayout.CMYKA40: case PixelLayout.Depth16: case PixelLayout.Depth24: case PixelLayout.Depth32: case PixelLayout.DepthF: case PixelLayout.Depth24Stencil8: case PixelLayout.Depth32FStencil8: case PixelLayout.Integer1: case PixelLayout.Integer2: case PixelLayout.Integer3: case PixelLayout.Integer4: case PixelLayout.UInteger1: case PixelLayout.UInteger2: case PixelLayout.UInteger3: case PixelLayout.UInteger4: _PixelBuffers = new AlignedMemoryBuffer(w * h * formatInfo.PixelBytes, 16); // Define planes _PixelPlanes = new IntPtr[] { _PixelBuffers.AlignedBuffer }; break; case PixelLayout.YUYV: case PixelLayout.YYUV: case PixelLayout.YVYU: case PixelLayout.UYVY: case PixelLayout.VYUY: if (((w % 2) != 0) || ((h % 2) != 0)) { throw new InvalidOperationException(String.Format("invalid image extents for pixel format {0}", format)); } // Define planes _PixelBuffers = new AlignedMemoryBuffer(w * h * formatInfo.PixelBytes, 16); _PixelPlanes = new IntPtr[] { _PixelBuffers.AlignedBuffer }; break; case PixelLayout.YVU410: case PixelLayout.YUV410: if (((w % 16) != 0) || ((h % 16) != 0)) { throw new InvalidOperationException(String.Format("invalid image extents for pixel format {0}", format)); } _PixelBuffers = new AlignedMemoryBuffer(w * h + (w * h / 16) * 2, 16); // Define planes _PixelPlanes = new IntPtr[3]; _PixelPlanes[0] = _PixelBuffers.AlignedBuffer; _PixelPlanes[1] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h); _PixelPlanes[2] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h + (w * h / 16)); break; case PixelLayout.YVU420: case PixelLayout.YUV420: if (((w % 4) != 0) || ((h % 4) != 0)) { throw new InvalidOperationException(String.Format("invalid image extents for pixel format {0}", format)); } _PixelBuffers = new AlignedMemoryBuffer(w * h + (w * h / 4), 16); // Define planes _PixelPlanes = new IntPtr[3]; _PixelPlanes[0] = _PixelBuffers.AlignedBuffer; _PixelPlanes[1] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h); _PixelPlanes[2] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h + (w * h / 4)); break; case PixelLayout.YUV422P: if ((w % 2) != 0) { throw new InvalidOperationException(String.Format("invalid image extents for pixel format {0}", format)); } _PixelBuffers = new AlignedMemoryBuffer(w * h + (w * h / 2), 16); // Define planes _PixelPlanes = new IntPtr[3]; _PixelPlanes[0] = _PixelBuffers.AlignedBuffer; _PixelPlanes[1] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h); _PixelPlanes[2] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h + (w * h / 2)); break; case PixelLayout.YUV411P: if ((w % 4) != 0) { throw new InvalidOperationException(String.Format("invalid image extents for pixel format {0}", format)); } _PixelBuffers = new AlignedMemoryBuffer(w * h + (w * h / 4), 16); // Define planes _PixelPlanes = new IntPtr[3]; _PixelPlanes[0] = _PixelBuffers.AlignedBuffer; _PixelPlanes[1] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h); _PixelPlanes[2] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h + (w * h / 4)); break; case PixelLayout.Y41P: if ((w % 8) != 0) { throw new InvalidOperationException(String.Format("invalid image extents for pixel format {0}", format)); } _PixelBuffers = new AlignedMemoryBuffer(w * h * 12 / 8, 16); // Define planes _PixelPlanes = new IntPtr[3]; _PixelPlanes[0] = _PixelBuffers.AlignedBuffer; _PixelPlanes[1] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h); _PixelPlanes[2] = new IntPtr(_PixelBuffers.AlignedBuffer.ToInt64() + w * h + (w * h / 4)); break; default: throw new NotSupportedException(String.Format("pixel format {0} is not supported", format)); } // Set image information _ImageInfo.PixelType = formatInfo.DataFormat; _ImageInfo.Width = w; _ImageInfo.Height = h; // Store pixel format _PixelFormat = formatInfo; Debug.Assert(_PixelPlanes != null); Debug.Assert(_PixelPlanes.Length != 0); Debug.Assert(Array.TrueForAll(_PixelPlanes, delegate(IntPtr pixelPlane) { return(pixelPlane != IntPtr.Zero); })); }
/// <summary> /// Copy data from another AlignedMemoryBuffer. /// </summary> /// <param name="otherMemoryBuffer"> /// A <see cref="AlignedMemoryBuffer"/> which has allocated the data to be copied. /// </param> /// <param name="otherOffset"> /// A <see cref="UInt64"/> which specify an additional offset (in bytes) to apply to <paramref name="otherMemoryBuffer"/>. /// </param> /// <param name="thisOffset"> /// A <see cref="UInt64"/> which specify an additional offset (in bytes) to apply to this AlignedMemoryBuffer. /// </param> /// <param name="bytesCopied"> /// A <see cref="UInt64"/> which specify the number of bytes to be copied. /// </param> public void CopyBuffer(AlignedMemoryBuffer otherMemoryBuffer, ulong otherOffset, ulong thisOffset, ulong bytesCopied) { if (IsDisposed) throw new ObjectDisposedException("AlignedMemoryBuffer"); if (otherMemoryBuffer == null) throw new ArgumentNullException("otherMemoryBuffer"); if (otherMemoryBuffer._UnmanagedBuffer == IntPtr.Zero) throw new ArgumentException("disposed", "otherMemoryBuffer"); if (thisOffset + bytesCopied >= otherMemoryBuffer.Size - otherOffset) throw new InvalidOperationException("copying out of bounds"); if (bytesCopied > 0) { IntPtr src = new IntPtr(otherMemoryBuffer.AlignedBuffer.ToInt64() + (long)otherOffset); IntPtr dst = new IntPtr(AlignedBuffer.ToInt64() + (long)thisOffset); Memory.MemoryCopy(dst, src, bytesCopied); } }