0
votes

I'm writting a GUI wich uses OpenGL via the OpenTK and the GLControl on C# and i'm trying to use dirty rectangles for drawing only the controls that need to be drawed. Obviusly it's not wise to redraw an entire maximized form just for refreshing a mouse-hover button.

My first attempt was to use glScissors but this doesn't limit the SwapBuffers, wich in my platform, I suspect (because of the performance almost entirely dependent on the window size) doesn't 'swap' but do a full copy of the back buffer onto the front buffer.

The second attempt was the glAddSwapHintRectWIN wich in theory would limit the swapped (in this case copied) area of the SwapBuffers, but this is only a hint and it doesn't do anything at all.

The third attempt was the glDrawBuffer to copy a part of the back buffer onto the frame buffer, for some unknown reason, even when i copy only a part of the buffer, the performance still decreases the same way before when the window size increase.

It seams that a full-area refresh it's still hapening no matter what i do.

So i'm trying to use the glReadPixels () and somehow get a pointer to draw directly onto a hDC pixel data getted from the CreateGraphics() of the control. Is this possible?

EDIT:

I think something is wrong with the GLControl, why the performance of this code depends on the screen size, i'm not doing any swapbuffers or clearing, just drawing a constant-size triangle on the front buffer:A driver problem, maybe?

        GL.DrawBuffer(DrawBufferMode.Front);

        Vector4 Color;
        Color = new Vector4((float)R.NextDouble(), 0, 0, 0.3F);

        GL.Begin(BeginMode.Triangles);

        GL.Color4(Color.X, Color.Y, Color.Z, Color.W);



        GL.Vertex3(50, 50, 0);
        GL.Vertex3(150F, 50F, 0F);
        GL.Vertex3(50F, 150F, 0F);

        GL.End();

        GL.Finish();

EDIT 2 This solutions are not viable: Drawing onto a texture and using glGetTexImage for drawing onto a GDI bitmap and then drawing that bitmap onto the window hDC

Reading buffer pixels from the buffer using glReadPixels onto a GDI bitmap and then drawing that bitmap onto the window hDC.

Splitting the window onto a grid of viewports and updating only the cells that contains the dirty rectangle

2
What does GL.GetString(StringName.Renderer) return?The Fiddler

2 Answers

1
votes

First of all, what platform (GPU and OS) are you using? What kind of performance are we talking about?

Keep in mind that there are several limitations when trying to combine GDI and OpenGL on the same hDC. Indeed, in most cases this will turn off hardware acceleration and give you OpenGL 1.1 through Microsoft's software renderer.

Hardware accelerated OpenGL is optimized for redrawing the entire window every frame. SwapBuffers() invalidates the contents of the backbuffer, which makes dirty rectangles impossible to implement when double buffering on the default framebuffer.

There are two solutions:

  1. do not call SwapBuffers(). Set GL.DrawBuffer(DrawBufferMode.Front) and use single-buffering to update the rectangles that are dirty. This has severe drawbacks, including turning off desktop composition on Windows.
  2. do not render directly to the default framebuffer. Instead, allocate and render into a framebuffer object. This way, you can update only the regions of the FBO that have been modified. (You will still need to copy the FBO to screen every frame, so it may or may not be a performance win depending on your GUI complexity.)

Edit:

40-60ms for a single triangle indicates that you are not getting any hardware acceleration. Check GL.GetString(StringName.Renderer) - does it give the name of your GPU or does it return "Microsoft GDI renderer"?

If it is the latter, then you must install OpenGL drivers from the website of your GPU vendor. Do that and the performance problem will disappear.

0
votes

After several test with OpenTK, it appears that in single or double buffered mode, the slowdown observed with control size increasing still remains, even with constant size scissor enabled. Even the use or not of GL.Clear() doesn't impact slowdown. (Note that only height changes has significant impact.)

Testing with ansi c example, I had the same results.

Making the same couple of tests under linux gave the same results too.

Under linux I noticed that frame rate changes when I move from one display to the other. Even with vsync disabled.

Next step would be to check if directX has the same behaviour. If yes, than the limitation is located on the bus between display and graphic card.

EDIT: conclusion:

This behaviour is leading you to false impression. Consider only building your interface on a FBO with dirty rect mechanisms and render it on a quad (made of tri's is better) and swap as usual without thinking that you can improve swapping for a given window size by clipping some operations.