TheMPC
Topic Author
Posts: 7
Joined: 29 May 2018, 23:25

C++ OpenGL/GLFW Integration - Question on rendering

09 Jun 2018, 17:02

Hi people,

I've started integrating Noesis GUI into my project which uses an OpenGL/GLFW rendering structure and I am using the sample GLRenderDevice for now until I got this working and can start to tinker with it, mostly this is going alright without many issues (took a few seconds to realize I had to reset OpenGL states after updating the RenderTree and Offscreen Render but that was it so far).

But now I've come across an issue I'm hard-pressed to find the solution to on my own and I'm hoping I could get some advice on this here.

The issue basically is that as soon as I call: UpdateRenderTree + RenderOffscreen + (My Rendering) + Render on the IRenderer interface, my application will refuse to show any updates to the FrameBufferObject. This causes it to look as if the application froze, but it's still running, just not showing changes made to the FBO.

I've done numerous tests to track down the issue, but to no avail, some things I've tried to narrow down the issue are:
  • Run without rendering my own geometry so only UI is visible
  • Bind a different FBO before calling Render, this didn't render the UI into the default FBO (0) but the screen still froze.
  • Clear the FBO just before swapping the buffers
Neither of the above resulted in succes, and the last test (see the code below) should at least show a cleared screen and not the FBO updated by the Render call.
while (!glfwWindowShouldClose(mWindow))
{
	// New Frame Stuff
	...
	// ~New Frame Stuff

	PROFILE_CUSTOM("Main Loop");
	{
		PROFILE_CUSTOM("GLFW");
		// Clear the colorbuffer
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		// Events
		glfwPollEvents();
	}

	// Game update
	...
	// ~Game update

	// UI Update
	if (mInGameMode)
	{
		// This is the part where UpdateRenderTree + RenderOffscreen are called.
		PROFILE_CUSTOM("UIManager Update");
		UIManager::GetInstance().Update();
	}

	// Render update
	// Also resets the OpenGL state as it was modified by Noesis GUI
	...
	// ~Render update

	// UI Render
	if (mInGameMode)
	{
		// This is the part where Render is called.
		PROFILE_CUSTOM("UIManager Render");
		UIManager::GetInstance().Render();
	}

	//End of loop, swap buffer
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	if (mInGameMode)
	{
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	}
	glfwSwapBuffers(mWindow);
}
In the code above mInGameMode defaults to false and is set to true on a hotkey, and resets back to false on another hotkey.
In my opinion this should always show a blank screen when mInGameMode is true, and it does do this when I disable the UIManager sections of the code.

For reference, the UIManager code:
void UIManager::Initialize()
{
	GUI::Init(
		[](const char* file, uint32_t line, const char* message, bool fatal) 
		{
			Logger::Log(fatal ? Logger::ELogSeverity::FatalError : Logger::ELogSeverity::Error, "Noesis UI", message);
		}, 
		[](const char* filename, uint32_t line, uint32_t level, const char* channel, const char* message) 
		{
			Logger::Log(Logger::ELogSeverity::Log, "Noesis UI", message);
		}, 
		nullptr
	);

	GUI::SetXamlProvider(MakePtr<UI_XamlProvider>());
	//GUI::SetTextureProvider(MakePtr<>());
	//GUI::SetFontProvider(MakePtr<>());

	NoesisApp::Launcher::RegisterAppComponents();

	NsRegisterComponent<NoesisUI::App>();
	NsRegisterComponent<NoesisUI::MainWindow>();

	int width, height;
	glfwGetFramebufferSize(OpenGLEngine::GetInstance().GetWindow(), &width, &height);

	Noesis::Ptr<Noesis::RenderDevice> device = NoesisApp::GLFactory::CreateDevice();
	device->SetGlyphCacheWidth(1024);
	device->SetGlyphCacheHeight(1024);
	device->SetGlyphCacheMeshThreshold(48);

	Ptr<FrameworkElement> xaml = Noesis::GUI::LoadXaml<FrameworkElement>("MainWindow");
	view = Noesis::GUI::CreateView(xaml);
	view->SetIsPPAAEnabled(true);
	view->GetRenderer()->Init(device);
	view->SetSize(width, height);

	RestoreValues();
}

void UIManager::Update()
{
	double time = glfwGetTime();
	view->Update(time);

	// Offscreen rendering phase populates textures needed by the on-screen rendering
	view->GetRenderer()->UpdateRenderTree();
	view->GetRenderer()->RenderOffscreen();

	// If you are going to render here with your own engine you need to restore the GPU state
	// because noesis changes it. The framebuffer and viewport are restored here
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	int width, height;
	glfwGetFramebufferSize(OpenGLEngine::GetInstance().GetWindow(), &width, &height);
	glViewport(0, 0, width, height);

	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClearStencil(0);
	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	RestoreValues();
}

void UIManager::Render()
{
	view->GetRenderer()->Render();

	RestoreValues();
}

void UIManager::RestoreValues()
{
	glEnable(GL_CULL_FACE);
	glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_TRUE);
	glDisable(GL_BLEND);
	glDisable(GL_STENCIL_TEST);
	glDisable(GL_SCISSOR_TEST);
	glStencilMask(0);
}
Any help or suggestions are appreciated.
 
User avatar
sfernandez
Site Admin
Posts: 1920
Joined: 22 Dec 2011, 19:20

Re: C++ OpenGL/GLFW Integration - Question on rendering

11 Jun 2018, 11:51

Hi,

I don't understand why you need to clear the framebuffer after rendering, and don't know if that is your problem.

The render loop should be quite simple:
LOOP START
{
  // Game and input update

  _noesisView->Update(timeInSeconds);

  _noesisRenderer->UpdateRenderTree();
  if (_noesisRenderer->NeedsOffscreen())
    _noesisRenderer->RenderOffscreen();

  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  // Reset GL state to initialize anything that Noesis could have changed during RenderOffscreen

  // Render your geometry

  _noesisRenderer->Render();

  glfwSwapBuffers(mWindow);

} LOOP END
 
TheMPC
Topic Author
Posts: 7
Joined: 29 May 2018, 23:25

Re: C++ OpenGL/GLFW Integration - Question on rendering

11 Jun 2018, 15:35

Correct, I do not need to, I did this as an experiment.

Basically with the setup you just showed the screen will freeze for me. Even if I clear the screen, it will not show an empty screen. Somehow it still shows the image generated by _noesisRenderer->Render(); even thought I tell the FBO to clear. I'm quite sure it's some OpenGL setting somewhere which causes this and I was hoping someone here might know the answer to it.
 
User avatar
sfernandez
Site Admin
Posts: 1920
Joined: 22 Dec 2011, 19:20

Re: C++ OpenGL/GLFW Integration - Question on rendering

11 Jun 2018, 16:38

If you comment all the noesis calls, are you able to render your 3D scene correctly, without freezing?

Then if you add the Noesis's Update, UpdateRenderTree and Render calls (without RenderOffscreen), are you able to render everything correctly?
NOTE: Start with a simple xaml with a red Rectangle and without opacity groups:
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Rectangle Width="200" Height="100" Fill="Red"/>
</Grid>
Is the RenderOffscreen, when added, the one causing your screen to freeze?
 
TheMPC
Topic Author
Posts: 7
Joined: 29 May 2018, 23:25

Re: C++ OpenGL/GLFW Integration - Question on rendering

11 Jun 2018, 17:56

If I comment out all the Noesis calls the 3D scene renders correctly and doesn't freeze, this is correct. I'm unable to test your suggestions at this moment but will be back in a few hours with the results of the suggested steps. I'll also use the xaml provided, as I'm currently using something similar to test anyway.
 
TheMPC
Topic Author
Posts: 7
Joined: 29 May 2018, 23:25

Re: C++ OpenGL/GLFW Integration - Question on rendering

11 Jun 2018, 19:37

Well I'm happy to say that using the xaml data you provided actually fixes the issue.

Though my confusion still haunts me as to why, for reference, this is the .xaml file saved from Blend:
<Window x:Class="NoesisUI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:NoesisUI"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Button Content="Test Button" HorizontalAlignment="Left" Margin="347.941,200.236,0,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>
I did some tinkering with it (removing variables bit by bit) and the Width="75" part is which break the entire thing, not sure if that's my doing with Blend or an issue in the system? I do know is that all I did in Blend was drag a button in somewhere in the window and save it. I can supply the Blend project if desired.

Edit: For more info, an example provided in the documentation which uses Width does work:
    <Grid>
	  <Button Width="60" Height="40" Content="OK">
		<Button.ToolTip>
		  Clicking this will submit your request
		</Button.ToolTip>
	  </Button>
	</Grid>
And adding a Height value to my original xaml doesn't solve it.

Edit 2: Even more info: After using the button example from the documentation I noticed that if I take the above xaml and change the "OK" Content to something larger (which doesn't fit in the button) I get screen freeze again.

So this doesn't work for me:
    <Grid>
	  <Button Width="60" Height="40" Content="OK OK OK OK OK OK">
		<Button.ToolTip>
		  Clicking this will submit your request
		</Button.ToolTip>
	  </Button>
	</Grid>
Last edited by TheMPC on 11 Jun 2018, 19:50, edited 1 time in total.
 
User avatar
sfernandez
Site Admin
Posts: 1920
Joined: 22 Dec 2011, 19:20

Re: C++ OpenGL/GLFW Integration - Question on rendering

11 Jun 2018, 19:47

If you set the Button's Width="300", then what happens? is it working fine?

My guess is that the problem is something related with the stencil buffer. We use stencil buffer when we need to do clipping, and maybe in your original xaml Button's width was not enough to fit the text "Test Button", so clipping was activated.

You need to create a stencil buffer for the main window surface and clear it on each frame.
 
TheMPC
Topic Author
Posts: 7
Joined: 29 May 2018, 23:25

Re: C++ OpenGL/GLFW Integration - Question on rendering

11 Jun 2018, 19:52

"You need to create a stencil buffer for the main window surface" This part for sure then! I did read about this in the rendering integration but didn't know how to achieve this, nor that it could cause such severe issues, I expected just to see no clipping instead of freezing I guess.

This solves everything, thank you for your time an patience!
 
User avatar
sfernandez
Site Admin
Posts: 1920
Joined: 22 Dec 2011, 19:20

Re: C++ OpenGL/GLFW Integration - Question on rendering

11 Jun 2018, 19:54

Great, glad to hear it is finally working. I'm setting this thread as solved.
 
TheMPC
Topic Author
Posts: 7
Joined: 29 May 2018, 23:25

Re: C++ OpenGL/GLFW Integration - Question on rendering

11 Jun 2018, 20:30

If you don't mind indulging me with some more info on the stencil buffer, which of the FBOs requires the stencil buffer, the one used by _noesisRenderer->Render(); or _noesisRenderer->RenderOffscreen();? As the following code does detail the default (0) FBO has an 8-bit stencil buffer:
GLint stencil_bits;
glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &stencil_bits);

Who is online

Users browsing this forum: No registered users and 1 guest