Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 75 additions & 8 deletions source/SharpGL/Core/SharpGL.WPF/OpenGLControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
Expand All @@ -17,6 +18,16 @@ namespace SharpGL.WPF
/// </summary>
public partial class OpenGLControl : UserControl
{
// Fields to support the WritableBitmap method of rendering the image for display
byte[] m_imageBuffer;
WriteableBitmap m_writeableBitmap;
Int32Rect m_imageRect;
int m_imageStride;
double m_dpiX = 96;
double m_dpiY = 96;
PixelFormat m_format = PixelFormats.Bgra32;
int m_bytesPerPixel = 32 >> 3;

/// <summary>
/// Initializes a new instance of the <see cref="OpenGLControl"/> class.
/// </summary>
Expand Down Expand Up @@ -105,6 +116,8 @@ private void UpdateOpenGLControl(int width, int height)
}
}
}
// Force re-creation of image buffer since size has changed
m_imageBuffer = null;
}

/// <summary>
Expand All @@ -123,6 +136,9 @@ public override void OnApplyTemplate()
gl.Create(OpenGLVersion, RenderContextType, 1, 1, 32, null);
}

// Force re-set of dpi and format settings
m_dpiX = 0;

// Create our fast event args.
eventArgsFast = new OpenGLEventArgs(gl);

Expand Down Expand Up @@ -184,10 +200,7 @@ void timer_Tick(object sender, EventArgs e)

if (hBitmap != IntPtr.Zero)
{
var newFormatedBitmapSource = GetFormatedBitmapSource(hBitmap);

// Copy the pixels over.
image.Source = newFormatedBitmapSource;
FillImageSource(provider.DIBSection.Bits, hBitmap);
}
}
break;
Expand All @@ -202,10 +215,7 @@ void timer_Tick(object sender, EventArgs e)

if (hBitmap != IntPtr.Zero)
{
var newFormatedBitmapSource = GetFormatedBitmapSource(hBitmap);

// Copy the pixels over.
image.Source = newFormatedBitmapSource;
FillImageSource(provider.InternalDIBSection.Bits, hBitmap);
}
}
break;
Expand Down Expand Up @@ -395,5 +405,62 @@ public OpenGL OpenGL
{
get { return gl; }
}

/// Fill the ImageSource from the provided bits IntPtr, using the provided hBitMap IntPtr
/// if needed to determine key data from the bitmap source.
/// </summary>


/// <param name="bits">An IntPtr to the bits for the bitmap image. Generally provided from
/// DIBSectionRenderContextProvider.DIBSection.Bits or from
/// FBORenderContextProvider.InternalDIBSection.Bits.</param>
/// <param name="hBitmap">An IntPtr to the HBitmap for the image. Generally provided from
/// DIBSectionRenderContextProvider.DIBSection.HBitmap or from
/// FBORenderContextProvider.InternalDIBSection.HBitmap.</param>
public void FillImageSource(IntPtr bits, IntPtr hBitmap)
{
// If DPI hasn't been set, use a call to HBitmapToBitmapSource to fill the info
// This should happen only ONCE (near the start of the application)
if (m_dpiX == 0)
{
var bitmapSource = BitmapConversion.HBitmapToBitmapSource(hBitmap);
m_dpiX = bitmapSource.DpiX;
m_dpiY = bitmapSource.DpiY;
m_format = bitmapSource.Format;
m_bytesPerPixel = gl.RenderContextProvider.BitDepth >> 3;
// FBO render context flips the image vertically, so transform to compensate
if (RenderContextType == SharpGL.RenderContextType.FBO)
{
image.RenderTransform = new ScaleTransform(1.0, -1.0);
image.RenderTransformOrigin = new Point(0.0, 0.5);
}
else
{
image.RenderTransform = Transform.Identity;
image.RenderTransformOrigin = new Point(0.0, 0.0);
}
}
// If the image buffer is null, create it
// This should happen when the size of the image changes
if (m_imageBuffer == null)
{
int width = gl.RenderContextProvider.Width;
int height = gl.RenderContextProvider.Height;

int imageBufferSize = width * height * m_bytesPerPixel;
m_imageBuffer = new byte[imageBufferSize];
m_writeableBitmap = new WriteableBitmap(width, height, m_dpiX, m_dpiY, m_format, null);
m_imageRect = new Int32Rect(0, 0, width, height);
m_imageStride = width * m_bytesPerPixel;
}

// Fill the image buffer from the bits and create the writeable bitmap
System.Runtime.InteropServices.Marshal.Copy(bits, m_imageBuffer, 0, m_imageBuffer.Length);
m_writeableBitmap.WritePixels(m_imageRect, m_imageBuffer, m_imageStride, 0);

image.Source = m_writeableBitmap;
}


}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using SharpGL.Version;

namespace SharpGL.RenderContextProviders
{
public class FBORenderContextProvider : HiddenWindowRenderContextProvider
{
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);

/// <summary>
/// Initializes a new instance of the <see cref="FBORenderContextProvider"/> class.
/// </summary>
Expand Down Expand Up @@ -60,6 +64,14 @@ public override bool Create(OpenGLVersion openGLVersion, OpenGL gl, int width, i
gl.FramebufferRenderbufferEXT(OpenGL.GL_FRAMEBUFFER_EXT, OpenGL.GL_DEPTH_ATTACHMENT_EXT,
OpenGL.GL_RENDERBUFFER_EXT, depthRenderBufferID);


if(usePBO)
{
pboIds = new uint[PBO_COUNT];
int byte_count = width * height * 4;
CreatePBOs((uint)byte_count, pboIds);
}

dibSectionDeviceContext = Win32.CreateCompatibleDC(deviceContextHandle);

// Create the DIB section.
Expand All @@ -68,6 +80,17 @@ public override bool Create(OpenGLVersion openGLVersion, OpenGL gl, int width, i
return true;
}

private void CreatePBOs(uint byte_count, uint[] ids)
{
gl.GenBuffersARB(PBO_COUNT, pboIds);
for (int i = 0; i < PBO_COUNT; ++i)
{
gl.BindBufferARB(OpenGL.GL_PIXEL_PACK_BUFFER_ARB, ids[i]);
gl.BufferDataARB(OpenGL.GL_PIXEL_PACK_BUFFER_ARB, byte_count, (IntPtr)0, OpenGL.GL_STREAM_READ_ARB);
}
gl.BindBufferARB(OpenGL.GL_PIXEL_PACK_BUFFER_ARB, 0);
}

private void DestroyFramebuffers()
{
// Delete the render buffers.
Expand All @@ -80,6 +103,11 @@ private void DestroyFramebuffers()
colourRenderBufferID = 0;
depthRenderBufferID = 0;
frameBufferID = 0;

if (usePBO)
{
gl.DeleteBuffersARB(PBO_COUNT, pboIds);
}
}

public override void Destroy()
Expand Down Expand Up @@ -141,22 +169,53 @@ public override void SetDimensions(int width, int height)
OpenGL.GL_RENDERBUFFER_EXT, colourRenderBufferID);
gl.FramebufferRenderbufferEXT(OpenGL.GL_FRAMEBUFFER_EXT, OpenGL.GL_DEPTH_ATTACHMENT_EXT,
OpenGL.GL_RENDERBUFFER_EXT, depthRenderBufferID);

if (usePBO)
{
CreatePBOs((uint)(width * height * 4), pboIds);
}
}

public override void Blit(IntPtr hdc)
{
if (deviceContextHandle != IntPtr.Zero)
{
// Set the read buffer.
gl.ReadBuffer(OpenGL.GL_COLOR_ATTACHMENT0_EXT);

// Read the pixels into the DIB section.
gl.ReadPixels(0, 0, Width, Height, OpenGL.GL_BGRA,
OpenGL.GL_UNSIGNED_BYTE, dibSection.Bits);

// Blit the DC (containing the DIB section) to the target DC.
Win32.BitBlt(hdc, 0, 0, Width, Height,
dibSectionDeviceContext, 0, 0, Win32.SRCCOPY);
if(!usePBO)
{
// Set the read buffer.
gl.ReadBuffer(OpenGL.GL_COLOR_ATTACHMENT0_EXT);

// Read the pixels into the DIB section.
gl.ReadPixels(0, 0, Width, Height, OpenGL.GL_BGRA,
OpenGL.GL_UNSIGNED_BYTE, dibSection.Bits);

// Blit the DC (containing the DIB section) to the target DC.
Win32.BitBlt(hdc, 0, 0, Width, Height,
dibSectionDeviceContext, 0, 0, Win32.SRCCOPY);
}
else
{
uint pbo_count = (uint)PBO_COUNT;
current_pbo_index = (current_pbo_index + 1) % pbo_count;
uint nextIndex = (current_pbo_index + pbo_count - 1) % pbo_count;
// Set the read buffer.
gl.ReadBuffer(OpenGL.GL_COLOR_ATTACHMENT0_EXT);

gl.BindBufferARB(OpenGL.GL_PIXEL_PACK_BUFFER_ARB, pboIds[current_pbo_index]);
gl.ReadPixels(0, 0, Width, Height, OpenGL.GL_BGRA, OpenGL.GL_UNSIGNED_BYTE, null);

// map the PBO that contain framebuffer pixels before processing it
gl.BindBufferARB(OpenGL.GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);
IntPtr src = gl.MapBufferARB(OpenGL.GL_PIXEL_PACK_BUFFER_ARB, OpenGL.GL_READ_ONLY_ARB);

CopyMemory(dibSection.Bits, src, (uint)(Width*Height*4));

// Blit the DC (containing the DIB section) to the target DC.
Win32.BitBlt(hdc, 0, 0, Width, Height,
dibSectionDeviceContext, 0, 0, Win32.SRCCOPY);

gl.UnmapBufferARB(OpenGL.GL_PIXEL_PACK_BUFFER_ARB);
}
}
}

Expand All @@ -167,6 +226,12 @@ public override void Blit(IntPtr hdc)
protected DIBSection dibSection = new DIBSection();
protected OpenGL gl;

protected bool usePBO = false;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set this to true to enable PBO based optimization

protected int PBO_COUNT = 2;
protected uint[] pboIds;
//protected
protected uint current_pbo_index = 0;

/// <summary>
/// Gets the internal DIB section.
/// </summary>
Expand Down