/// <inheritdoc/> public override void Attach(RenderBuffer2D buffer) { Contract.Require(buffer, nameof(buffer)); Contract.Ensure <ArgumentException>( buffer.Width == width && buffer.Height == height, OpenGLStrings.RenderBufferIsWrongSize); Contract.EnsureNotDisposed(this, Disposed); Ultraviolet.ValidateResource(buffer); var oglBuffer = (OpenGLRenderBuffer2D)buffer; Ultraviolet.QueueWorkItem(state => { using (OpenGLState.ScopedBindFramebuffer(framebuffer)) { AttachRenderBuffer(oglBuffer); framebufferStatus = gl.CheckNamedFramebufferStatus(framebuffer, gl.GL_FRAMEBUFFER); gl.ThrowIfError(); } }).Wait(); oglBuffer.MarkAttached(); buffers.Add(oglBuffer); }
/// <summary> /// Gets the render target's data. /// </summary> /// <param name="data">An array to populate with the render target's data.</param> /// <param name="region">The region of the render target from which to retrieve data.</param> private unsafe void GetDataInternal(Color[] data, Rectangle region) { using (OpenGLState.ScopedBindFramebuffer(framebuffer, true)) { fixed(Color *pData = data) { if (gl.IsReadBufferAvailable) { gl.ReadBuffer(gl.GL_COLOR_ATTACHMENT0); gl.ThrowIfError(); } gl.ReadPixels(region.X, region.Y, region.Width, region.Height, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, pData); gl.ThrowIfError(); } } // OpenGL texture data is stored upside down and in the wrong color format, // so we need to convert that to what our caller expects. var rowsToProcess = (Height % 2 == 0) ? Height / 2 : 1 + Height / 2; for (int y = 0; y < rowsToProcess; y++) { var ySrc = (y); var yDst = (Height - 1) - y; for (int x = 0; x < Width; x++) { var ixSrc = (ySrc * Width) + x; var ixDst = (yDst * Width) + x; var colorSrc = new Color(data[ixSrc].PackedValue); var colorDst = new Color(data[ixDst].PackedValue); data[ixDst] = colorSrc; data[ixSrc] = colorDst; } } }
/// <inheritdoc/> public override void Invalidate(Boolean color, Boolean depth, Boolean stencil, Boolean depthStencil, Int32 colorOffset, Int32 colorCount) { Contract.EnsureNotDisposed(this, Disposed); // If we don't have any support for framebuffer invalidation, simply do nothing. if (!gl.IsFramebufferInvalidationAvailable) { return; } // If we're relying on EXT_discard_framebuffer, then we can only discard the first color // attachment. If that leaves us with nothing to do, bail out. if (!gl.IsInvalidateSubdataAvailable) { if (colorOffset != 0) { color = false; if (!depth && !stencil && !depthStencil) { return; } } if (colorCount > 1) { colorCount = 1; } } // Bind the framebuffer (if we're not using DSA) and perform the invalidation. unsafe { var numAttachments = (color ? colorCount : 0) + (depth ? 1 : 0) + (stencil ? 1 : 0) + (depthStencil ? 1 : 0); var attachments = stackalloc UInt32[numAttachments]; var attachmentsIx = 0; if (color) { for (int i = 0; i < colorCount; i++) { attachments[attachmentsIx++] = (UInt32)(gl.GL_COLOR_ATTACHMENT0 + colorOffset + i); } } if (depth) { attachments[attachmentsIx++] = gl.GL_DEPTH_ATTACHMENT; } if (stencil) { attachments[attachmentsIx++] = gl.GL_STENCIL_ATTACHMENT; } if (depthStencil) { attachments[attachmentsIx++] = gl.GL_DEPTH_STENCIL_ATTACHMENT; } if (gl.IsInvalidateSubdataAvailable) { // The EXT DSA extension doesn't seem to provide glInvalidateNamedFramebuffer, so... using (OpenGLState.ScopedBindFramebuffer(framebuffer, gl.IsEXTDirectStateAccessAvailable)) { if (gl.IsEXTDirectStateAccessAvailable) { gl.InvalidateFramebuffer(gl.GL_FRAMEBUFFER, numAttachments, (IntPtr)attachments); gl.ThrowIfError(); } else { gl.InvalidateNamedFramebufferData(gl.GL_FRAMEBUFFER, framebuffer, numAttachments, (IntPtr)attachments); gl.ThrowIfError(); } } } else { using (OpenGLState.ScopedBindFramebuffer(framebuffer, true)) { gl.DiscardFramebufferEXT(gl.GL_FRAMEBUFFER, numAttachments, (IntPtr)attachments); gl.ThrowIfError(); } } } }