the Fiddler's picture

OpenTK and WPF interoperation

Project:The Open Toolkit library
Version:all versions
Component:Code
Category:support request
Priority:normal
Assigned:Unassigned
Status:closed
Description

Right now, it is possible to create an OpenTK.GLControl and host it in a WPF using a WindowsFormsHost.

The question is: can we create an OpenGL context directly on a WPF window and do away with the host control?

The attached solution creates a WPF solution, obtains its handle and creates a GraphicsContext. This works without errors, however OpenGL rendering results in artifacts. The msdn entry for the OnRender method, notes that:

msdn wrote:

The rendering instructions for this element are not used directly when this method is invoked, and are instead preserved for later asynchronous use by layout and drawing.

This explains why the rendering artifacts appear: OpenGL tries to render to the window directly and does not participate into WPF composition.

One *could* use offscreen OpenGL rendering, perform a readback and present the results into the WPF window, but this is inefficient. It would be nice to find a better solution or confirm that it cannot be done.

Any ideas?

AttachmentSize
OpenTKWPF.zip1.81 MB

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

#1

A related discussion on the msdn forums indicates that:

Quote:

I don't know why, but overriding OnRender does not work when the class is Window or derives from Window. That's the only reason I can think of that this method wouldn't work.

Most commonly, only classes the derive from FrameworkElement override OnRender. Most applications use pre-existing classes that derive from FrameworkElement rather than making their own.

Maybe overriding from FrameworkElement would yield better results?

Edit: same question on stackoverflow.

the Fiddler's picture

#2

This post outlines a potential solution that is trivial to adopt to OpenTK: Managed DirectX Interop with WPF.

They still use a WindowsFormsHost to host the DirectX control but render a transparent overlay on top it. This way, they can receive input events and host WPF controls on top of the WindowsFormsHost without introducing airspace issues. Quite nice!

viewon01's picture

#3

Hi,

Here is a solution to have a 100% WPF control drawing OpenGL.

I'm still working on ...

It is currently based on Tao, but currently we only have to got a solution... after we can convert it to OpenTk.

Performance

I think that there are several ways to improve it , it sounds that not creating a WGL context, but draw into a FBO (http://www.opentk.com/doc/graphics/frame-buffer-objects)

I have no experience with FBO and do not know to have a "MakeCurrent" method based on this... I hope you will find some time to help me.

If you can help me to avoid to create a WindowsForm control and draw only in memory ?

Issues

When I use the SimpleOpenGLControl (Tao) or the OpenTk GLControl.... in the WindowsHostForm I got some refreshing problems.

Here I got the same problem...

AttachmentSize
WPF_ogl.zip4.45 KB
the Fiddler's picture

#4

Status:open» in progress (review)
viewon01's picture

#5

Hi,

I have a new version...

The difference is that we create a BitmapSource at startup and then we use glReadPixel to put the image directly in the image.
Like this we avoid one copy.

But I have a question, it sounds that glReadPixel do not always read the "right" buffer or that maybe it read a previous image.
Is it possible ?

Thanks

AttachmentSize
WPF4_ok_fast01.zip5.31 KB
zahirtezcan's picture

#6

if you are using framebuffer for offline rendering (render to texture then glReadPixels to memory bitmap); it is most likely to utilize pixel buffer objects(PBO) with double buffering. for detailed info: PBO

the Fiddler's picture

#7

Yes, it is possible. Make sure you call SwapBuffers or GL.Finish() just before you call GL.ReadPixels.

viewon01's picture

#8

Thanks,

But why calling SwapBuffer ? It sounds that we have 2 buffers... it will be better if we can always play with one buffer...

Is there a way to force glReadPixel to read on the "drawing" buffer ?

The second buffer is the WPF image... so we also avoid the flickering effect.

the Fiddler's picture

#9

You can use GL.ReadBuffer() to instruct GL.ReadPixels() to read from the backbuffer.

You can also request a single-buffered context (use a GraphicsContext constructor that takes a "buffers" argument), but note that this is not supported very well on modern operating systems (Aero might turn off, for example).

viewon01's picture

#10

Thanks

I use glReadBuffer and glReadPixels but doesn't see any performance improvement .

When I use GL_AUX0 it doesn't work !! I got no image !

MakeCurrent();
 
                Gl.glDrawBuffer(Gl.GL_AUX1);
 
                if (OnOGLRender != null)
                    OnOGLRender(null, null);
 
                //SwapBuffers();
 
                Gl.glFlush();
                Gl.glFinish();
 
                Gl.glReadBuffer(Gl.GL_AUX1);
                Gl.glReadPixels(0, 0, _form.ClientSize.Width, _form.ClientSize.Height, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, _bitmapSourceBuffer.BufferPointer);