Multithreaded object loading while rendering with OpenGL - c

I want to load some textures and meshes in a separate thread while the main program is showing a loading screen because it takes a few seconds to load all resources. I'm using OpenGL and GLFW. I tried to accomplish this with the following code:
void *status;
if(pthread_create(&loader, NULL, &loader_func, NULL))
{
fprintf(stderr, "Error creating loader thread\n");
return 1;
}
while(_flags & FLAG_LOADING)
{
vec3 color = { 0.1, 0.3, 1.0 };
if(glfwWindowShouldClose(window))
{
resource_destroy();
glfwTerminate();
return 0;
}
GL_CHECK(glClearColor(0.1, 0.1, 0.1, 1.0));
GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
font_renderer_activate();
render_string(&_font_menu, "Loading...", _width / 2, _height / 2, 64,
color, ALIGN_V_CENTER | ALIGN_H_CENTER);
glfwSwapBuffers(window);
glfwPollEvents();
}
if(pthread_join(loader, &status))
{
fprintf(stderr, "Error joining loader and main thread\n");
return 1;
}
if(*(int *)status)
{
fprintf(stderr, "Error loading resources\n");
return 1;
}
loader_func() is not rendering to the screen, and only uses OpenGL functions for creating VAOs, VBOs etc. and loading data into them.
The problem is that after the loading text shows up on screen and loading has finished, nothing shows up on screen (EDIT: except the textual HUD) and I'm getting a lot of debug error messages in my log (I'm wrapping all OpenGL calls in a macro that checks for errors with glGetError):
main.c:588
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap_texture);
GL_Error 0x502: GL_INVALID_OPERATION
main.c:589
glDrawArrays(GL_TRIANGLES, OFFSET_SKYBOX, VERTICES_SKYBOX);
GL_Error 0x502: GL_INVALID_OPERATION
main.c:629
glDrawArrays(GL_TRIANGLES, OFFSET_SELECTOR, VERTICES_SELECTOR);
GL_Error 0x502: GL_INVALID_OPERATION
When I call loader_func directly, there are no errors and the main render loop works correctly.
I read that to use OpenGL functions in another thread it is required to call glfwMakeContextCurrent but that wouldn't work in my case, because then the loading screen wouldn't be rendered. My only idea was to utilize a second library like SDL to create a window while loading, then destroy it and create a new window with GLFW for use with OpenGL. Is that what I want to achieve possible with just OpenGL?

The easiest way to handle this is to have the main thread create and manage all of the OpenGL objects, while the loading thread does the File IO (easily the slowest part of the loading). Once the loading thread is finished with loading a particular asset, it can deliver the loaded data to the main thread via <insert your favorite thread-safe mechanism here>, which can do the final OpenGL uploading part.
After all, it's not like rendering a loading screen is a huge performance drain or something, so the cost of uploading on the main thread will be minimal. This also permits you to do that loading bar thing, since your main thread will frequently be getting the results of the loading process, so it knows at any time how much of the loading is finished.
If you absolutely must have two threads both making OpenGL calls for some reason, then you should also have two OpenGL contexts, each being current in a different thread, and the two contexts sharing objects with each other. GLFW is perfectly happy to provide this if you ask it nicely. Create your main window as normal, then set the GLFW_VISIBLE hint to GLFW_FALSE, and create a second window (with an arbitrary resolution). You should pass the main window as the last parameter to glfwCreateWindow, so that the two contexts can share objects. You can then set each window current in different contexts and you're fine.
One word of caution. Contexts that share objects between them only share certain objects. Objects which reference other objects cannot be shared (also query objects are unsharable for some reason). VAOs reference buffer objects, so they can't be shared. So there's no point in trying to create them on the off-screen context.

Related

Call OpenGL functions outside of the GtkGLArea signals

I am trying to create a library where it's possible to create a OpenGL context with GTK3 which gets rendered automatically or with 1 function call (something similar to a swap-buffers function). I was looking at the source code of GtkGLArea, which seems to have the following order of execution:
A new GtkGLArea is created with the superclass GtkWidget.
When the realize signal of the superclass is captured, a GdkGLContext
is created and a realize signal is given to the user. The user is supposed to put the initial OpenGL functions in a function passed to this signal.
The draw signal of the superclass is also captured, some OpenGL initialization code is called for binding the framebuffer (or texture) and the renderbuffer. The buffers are created if they don't exist. After this the render signal is given where the user is supposed to put the rendering OpenGL code. Finally the gdk_cairo_draw_from_gl function is called to draw the renderbuffer (or texture) on the Cairo context of the superclass passed through the draw signal.
For the user it basically comes down to this:
void realize(GtkGLarea *area){
// OpenGL initialization functions
}
gboolean render(GtkGLArea *area, GdkGLContext *context){
// OpenGL rendering functions
return TRUE;
}
// Init functions, setup a GTK window
GtkWidget *gl_area = gtk_gl_area_new();
g_signal_connect(gl_area, "realize", G_CALLBACK(realize), NULL);
g_signal_connect(gl_area, "render", G_CALLBACK(render), NULL);
// Add gl_area to the window and display the window
But that's not what I want, what I want is this:
// Init functions, setup a GTK window
// Setup a OpenGL context on the GTK window
// OpenGL initialization functions
while(1){ // Main loop
if(gtk_events_pending()){
gtk_main_iteration();
}
// OpenGL rendering functions
swapBuffers();
}
What would be the best way to achieve this? I tried this (unsuccessfully) by simulating the functions called around the signals, and by using a GdkGLContext created on a GdkWindow taken from a GtkDrawingArea.
These are the options which I can imagine as solutions now:
Create a custom GTK3 class extending GtkWidget and using GdkGLContext and somehow track when the drawing signal is called so the appropriate OpenGL functions are called around that signal.
Find a way to ignore the whole GTK3 part and try to use the underlying Xlib functions to create a OpenGL context through X11 (which isn't portable at all).
Use a evil hack with threads and setjmp and longjmp to enter and exit the signals from the swapBuffers function.
None of these "solutions" are really appealing to me, is the thing I want impossible, or am I just missing some information?

D3DImage and SharpDX flickering on slow hardware

I am using the SharpDX.WPF project for the WPF abilities, it seems like an easy to understand low-overhead library, compared to the Toolkit that comes with SharpDX (which has the same issue!)
First: I fixed the SharpDX.WPF project for the latest SharpDX using the following: https://stackoverflow.com/a/19791534/442833
Then I made the following hacky adjustment to DXElement.cs, a solution that was also done here:
private Query queryForCompletion;
public void Render()
{
if (Renderer == null || IsInDesignMode)
return;
var test = Renderer as D3D11;
if (queryForCompletion == null)
{
queryForCompletion = new Query(test.Device,
new QueryDescription {Type = QueryType.Event, Flags = QueryFlags.None});
}
Renderer.Render(GetDrawEventArgs());
Surface.Lock();
test.Device.ImmediateContext.End(queryForCompletion);
// wait until drawing completes
Bool completed;
var counter = 0;
while (!(test.Device.ImmediateContext.GetData(queryForCompletion, out completed)
&& completed))
{
Console.WriteLine("Yielding..." + ++counter);
Thread.Yield();
}
//Surface.Invalidate();
Surface.AddDirtyRect(new Int32Rect(0, 0, Surface.PixelWidth, Surface.PixelHeight));
Surface.Unlock();
}
Then I render 8000 cubes in a cube pattern...
Yielding...
gets printed to the console quite often, but the flickering is still there.
I am assuming that WPF is nice enough to show the image using a different thread before the rendering is done, not sure though...
This same issue also happens when I use the Toolkit variant of WPF support with SharpDX.
Images to demonstate the issue:
Bad
Better
Almost
Intended
Note: It randomly switches between these old images, randomly. I am also using really old hardware which makes the flickering much more appearant (GeForce Quadro FX 1700)
A made a repo which contains the exact same source-code as I am using to get this issue:
https://github.com/ManIkWeet/FlickeringIssue/
Related to D3DImage locking, note that the D3DImage.TryLock API has rather unconventional semantics which most developers would not expect:
Beware!
You must call Unlock even in the case where TryLock indicates failure (i.e., returns false)
Although perhaps more of an alarming design choice than a bug per se, misunderstanding this behavior will trivially result in D3DImage deadlocks and hangs, and thus might be responsible for much of the frustration people experience in attempting to get D3DImage working properly.
The following code is a correct WPF D3D render with no flicker in my app:
void WPF_D3D_render(IntPtr pSurface)
{
if (TryLock(new Duration(default(TimeSpan))))
{
SetBackBuffer(D3DResourceType.IDirect3DSurface9, pSurface);
AddDirtyRect(new Int32Rect(0, 0, PixelWidth, PixelHeight));
}
Unlock(); // <--- !
}
Yes, this unintuitive code is actually correct; it is the case that that D3DImage.TryLock(0) leaks one internal D3D buffer lock every time it returns failure. You don't have to take my word for it, here's the CLR code from PresentationCore.dll v4.0.30319:
private bool LockImpl(Duration timeout)
{
bool flag = false;
if (_lockCount == uint.MaxValue)
throw new InvalidOperationException();
if (_lockCount == 0)
{
if (timeout == Duration.Forever)
flag = _canWriteEvent.WaitOne();
else
flag = _canWriteEvent.WaitOne(timeout.TimeSpan, false);
UnsubscribeFromCommittingBatch();
}
_lockCount++;
return flag;
}
Notice that the internal _lockCount field is incremented regardless of whether the function returns success or failure. You have to call Unlock() yourself, as shown in the first code example above, if you want to avoid certain deadlock. Failing to do so creates is nasty to debug, too, because the component won't (potentially) deadlock until the next render pass, by which time the relevant evidence is long gone.
The unusual behavior does not seem to be mentioned at MSDN, but to be fair, that documentation doesn't note that you have to call Unlock() if the call is successful, either.
The problem is not the Locking mechanism. Normally you use Present to draw to present the image. Present will wait until all drawing is ready. With D3DImage you are not using the Present() method. Instead of Presenting, you lock, adding a DirtyRect and unlock the D3DImage.
The rendering is done asynchrone so when you are unlocking, the draw actions might not be ready. This is causing the flicker effect. Sometimes you see items half drawn. A poor solution (i've tested with) is adding a small delay before unlocking. It helped a little, but it wasn't a neat solution. It was terrible!
Solution:
I continued with something else; I was expirimenting with MSAA (antialiasing) and the first problem I faced was; MSAA cannot be done on the dx11/dx9 shared texture, so i decided to render to a new texture (dx11) and create a copy to the dx9 shared texture. I slammed my head on the tabel, because now it was anti-aliased AND flicking-free!! Don't forget to call Flush() before adding a dirty rect.
So, creating a copy of the texture: DXDevice11.Device.ImmediateContext.ResolveSubresource(_dx11RenderTexture, 0, _dx11BackpageTexture, 0, ColorFormat); (_dx11BackpageTexture is shared texture) will wait until the rendering is ready and will create a copy.
This is how I got rid of the flickering....
I think you are not locking properly. As far as I understand the MSDN documentation you are supposed to lock during the entire rendering not just at the end of it:
While the D3DImage is locked, your application can also render to the Direct3D surface assigned to the back buffer.
The information you find on the net about D3DImage/SharpDX is somewhat confusing because the SharpDX guys don't really like the way D3DImage is implemented (can't blame them), so there are statements about this being a "bug" on Microsofts side when its actually just improper usage of the API.
Yes, locking during rendering has performance issues, but it is probably not possible to fix them without porting WPF to DirectX11 and implementing something like a SwapChainPanel which is available in UWP apps. (WPF itself still runs on DirectX9)
If the locking is a performance issue for you, one idea I had (but never tested) is that you could render to an offscreen surface and reduce the lock duration to copying that surface over to the D3DImage. No idea if that would help performance wise but its something to try.

Gtk and C - Multi-threaded GUI Application and Removing Global Variables

I have the example GTK C application from [1] building and working as expected. I have a pretty little UI application with a + and - button to increment/decrement a value stored in a global variable, and render it in the application in a text label.
I rarely ever work with GUI applications, and I do 99% of my work in C. I have two key questions with respect to tidying up this example and using it as the basis of a project.
Is it possible to have some alternative to global variables, like a
custom struct I create in main(), and have every callback handler reference
it by changing the function protocol for increase()?
Code:
// Can this function protocol be modified?
void increase(GtkWidget *widget, gpointer label) {
count++;
sprintf(buf, "%d", count);
gtk_label_set_text(GTK_LABEL(label), buf);
}
g_signal_connect(minus, "clicked", G_CALLBACK(decrease), label);
Is there a simple means of creating a separate thread to help manage the GUI? For example, if I have a button tied/connected to a function that would take a minute to complete, is there a universally-accepted means of firing off a separate pthread that allows me to have a button or command to cancel the operation, rather than the entire UI app being blocked for the whole minute?
Thank you.
References
Cross Compiling GTK applications For the Raspberry Pi, Accessed 2014-02-20, <http://hertaville.com/2013/07/19/cross-compiling-gtk-applications-for-the-raspberry-pi/>
Yes, you can pass anything you like as the last argument to signal handlers (gpointer is a typedef for void*) just create the structure containing the label widget and the counter variable in main(), pass it as the last argument to g_signal_connect and cast it back to the proper type in your callback.
For running a calculation in another thread and delivering the result to the gtk main loop I'd look at GTask, in particular g_task_run_in_thread_async.

FrameBuffer to file inside libgdx or OpenGL

I am trying to take screenshots in the most efficient way. I thing using a FrameBuffer is the most efficient way of taking screenshots because i can process the data in different thread than rendering thread.
How can i get the information from FrameBUffer and transfer it to a file?
FrameBuffer m_fbo;
render(){
m_fbo = new FrameBuffer(Format.RGB565, (int)(w * m_fboScaler), (int)(h * m_fboScaler), false);
m_fboRegion = new TextureRegion(m_fbo.getColorBufferTexture());
m_fboRegion.flip(false, true);
m_fbo.begin();
...rendering...
m_fbo.end();
writeTextureRegionToFile(); - i need some lines of code for the implementation of this method
}
The FrameBuffer contents reside in memory managed by OpenGL, so you will (as far as I understand things) still need to fetch those bytes using OpenGL APIs on the render thread. Specifically, you want the ScreenUtils class
to get a byte[] containing the RGBA8888 contents of your FrameBuffer.
Once you get the raw bytes, you can do any compression/conversion/output on a different thread, of course. There is a forum post that has a quick and dirty PNG writer. The Libgdx-specific (?) CIM format is also an option (see the PixmapIO class), but you'll have to convert the bytes into a Pixmap first.

OpenGL: secondary thread for loading resources?

Working with C and Win32, I would like to know how to implement a secondary OpenGL thread for loading resources(textures and VBOs).
From what I found, this should be done with wglShareLists(), but I am unsure about how to set up the secondary thread:
Do I need a new device context or only a new rendering context?
What wgl functions do I need to call?
You don't need a new context because you can reuse the same device context of the first one. Btw, you can specify another device context, but depending on your platform you should take care about it (on Windows, device contextes must have the same pixel format), otherwise you could fail to share objects between two contextes
Create both context in the main thread, the second one sharing with the first one. Then, make the first one current on the main thread, while making the other one current on the secondary thread.
Note that you can share with any render context: all sharing contextes "see" the same object by its name, indeed they share an object name space. Two different object name spaces (i.e. two non-sharing contextes) can have defined the same object (i.e. texture object name is 1), but the same name actually points to different object depending on the current context.
Objects created by the secondary thread are visible concurrently and consistently. However, not all objects can be shared across contextes. Keep in mind that sometimes it happens that the driver supports unexpected objects, and other times it happens that driver doesn't support correctly an expected object.
OpenGL is becoming an object oriented language. You can see a certain pattern for creating objects:
Generate name (GenTextures, GenBuffers)
Define object (BindTexture, BindBuffer)
Object existence (IsTexture, IsShader, IsFramebuffer)
Delete name (and object)
(Note that an object created with Gen routines exists only when they are bound)
Object classes could be
Display lists
Texture objects
Buffer objects
Shader objects and program objects
Renderbuffer objects
Framebuffer objects
Query objects
Sync objects
Transform feedback objects
I would suggest to use a "runtime" test, like the following:
private bool TestSharingObject(RenderContext rContextShare)
{
uint texture = 0;
// rContextShader is a context sharing with this RenderCOntext
this.MakeCurrent(true);
if (Caps.TextureObject.Supported == true) {
// Generate texture name
Gl.GenTextures(1, out texture);
// Ensure existing texture object
Gl.BindTexture(Gl.TEXTURE_2D, texture);
Gl.BindTexture(Gl.TEXTURE_2D, 0);
// Self test
if (Gl.IsTexture(texture) == false)
throw new NotSupportedException();
}
// Make current sharing context
rContextShare.MakeCurrent(true);
return ((texture != 0) && (Gl.IsTexture(texture) == true));
}
Another suggestion would be to run on secondary thread operations that are CPU intensive, and not directly affecting drawing system windows buffers. A good example would be a shader compilation, since the compilation runs on CPU side; keep also in mind that the driver could async your operations, and that OpenGL implementations may pipeline different operations..
Load resources however you need to in your secondary thread and then pass ownership of them back to your primary for the GL calls.
Sharing "lists" between GL contexts should work. Doing all your GL calls on your primary thread does work :)
It works!, only if wglShareLists is done by the main thread for all the worker thread.
Using message map, pass the reference of rendering context and make the main thread create the rendering context, use wglShareLists by main thread alone. Then call wglMakeCurrent on the worker thread with the rendering context created by main thread. It is imperative that wglShareLists is called before any gl operation is done on the rendering context. This is due to the requirement on parameter hglrc2(the OpenGL rendering context to share display lists with hglrc1), that it should not contain any existing display lists when wglShareLists is called.

Resources