+ mImpl->currentContext->BindFramebuffer( GL_FRAMEBUFFER, 0u );
+ }
+
+ if ( !instruction.mFrameBuffer )
+ {
+ mImpl->currentContext->Viewport( surfaceRect.x,
+ surfaceRect.y,
+ surfaceRect.width,
+ surfaceRect.height );
+ }
+
+ // Clear the entire color, depth and stencil buffers for the default framebuffer, if required.
+ // It is important to clear all 3 buffers when they are being used, for performance on deferred renderers
+ // e.g. previously when the depth & stencil buffers were NOT cleared, it caused the DDK to exceed a "vertex count limit",
+ // and then stall. That problem is only noticeable when rendering a large number of vertices per frame.
+ GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
+
+ mImpl->currentContext->ColorMask( true );
+
+ if( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE )
+ {
+ mImpl->currentContext->DepthMask( true );
+ clearMask |= GL_DEPTH_BUFFER_BIT;
+ }
+
+ if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE)
+ {
+ mImpl->currentContext->ClearStencil( 0 );
+ mImpl->currentContext->StencilMask( 0xFF ); // 8 bit stencil mask, all 1's
+ clearMask |= GL_STENCIL_BUFFER_BIT;
+ }
+
+ if( !instruction.mIgnoreRenderToFbo && ( instruction.mFrameBuffer != 0 ) )
+ {
+ // Offscreen buffer rendering
+ if ( instruction.mIsViewportSet )
+ {
+ // For glViewport the lower-left corner is (0,0)
+ const int32_t y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y;
+ viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
+ }
+ else
+ {
+ viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
+ }
+ surfaceOrientation = 0;
+ }
+ else // No Offscreen frame buffer rendering
+ {
+ // Check whether a viewport is specified, otherwise the full surface size is used
+ if ( instruction.mIsViewportSet )
+ {
+ // For glViewport the lower-left corner is (0,0)
+ const int32_t y = ( surfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y;
+ viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height );
+ }
+ else
+ {
+ viewportRect = surfaceRect;
+ }
+ }
+
+ if( surfaceOrientation == 90 || surfaceOrientation == 270 )
+ {
+ int temp = viewportRect.width;
+ viewportRect.width = viewportRect.height;
+ viewportRect.height = temp;
+ }
+
+ bool clearFullFrameRect = true;
+ if( instruction.mFrameBuffer != 0 )
+ {
+ Viewport frameRect( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
+ clearFullFrameRect = ( frameRect == viewportRect );
+ }
+ else
+ {
+ clearFullFrameRect = ( surfaceRect == viewportRect );
+ }
+
+ mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height);
+
+ if( instruction.mIsClearColorSet )
+ {
+ mImpl->currentContext->ClearColor( clearColor.r,
+ clearColor.g,
+ clearColor.b,
+ clearColor.a );
+
+ if( !clearFullFrameRect )
+ {
+ mImpl->currentContext->SetScissorTest( true );
+ mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height );
+ mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR );
+ mImpl->currentContext->SetScissorTest( false );
+ }
+ else
+ {
+ mImpl->currentContext->SetScissorTest( false );
+ mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR );
+ }
+ }
+
+ // Clear the list of bound textures
+ mImpl->boundTextures.Clear();
+
+ mImpl->renderAlgorithms.ProcessRenderInstruction(
+ instruction,
+ *mImpl->currentContext,
+ mImpl->renderBufferIndex,
+ depthBufferAvailable,
+ stencilBufferAvailable,
+ mImpl->boundTextures,
+ surfaceOrientation );
+
+ // Synchronise the FBO/Texture access when there are multiple contexts
+ if ( mImpl->currentContext->IsSurfacelessContextSupported() )
+ {
+ // Check whether any binded texture is in the dependency list
+ bool textureFound = false;
+
+ if ( mImpl->boundTextures.Count() > 0u && mImpl->textureDependencyList.Count() > 0u )
+ {
+ for ( auto textureId : mImpl->textureDependencyList )
+ {
+
+ textureFound = std::find_if( mImpl->boundTextures.Begin(), mImpl->boundTextures.End(),
+ [textureId]( GLuint id )
+ {
+ return textureId == id;
+ } ) != mImpl->boundTextures.End();
+ }
+ }
+
+ if ( textureFound )
+ {
+ if ( instruction.mFrameBuffer )
+ {
+ // For off-screen buffer
+
+ // Wait until all rendering calls for the currently context are executed
+ mImpl->glContextHelperAbstraction.WaitClient();
+
+ // Clear the dependency list
+ mImpl->textureDependencyList.Clear();
+ }
+ else
+ {
+ // Worker thread lambda function
+ auto& glContextHelperAbstraction = mImpl->glContextHelperAbstraction;
+ auto workerFunction = [&glContextHelperAbstraction]( int workerThread )
+ {
+ // Switch to the shared context in the worker thread
+ glContextHelperAbstraction.MakeSurfacelessContextCurrent();
+
+ // Wait until all rendering calls for the shared context are executed
+ glContextHelperAbstraction.WaitClient();
+
+ // Must clear the context in the worker thread
+ // Otherwise the shared context cannot be switched to from the render thread
+ glContextHelperAbstraction.MakeContextNull();
+ };
+
+ auto future = mImpl->threadPool->SubmitTask( 0u, workerFunction );
+ if ( future )
+ {
+ mImpl->threadPool->Wait();
+
+ // Clear the dependency list
+ mImpl->textureDependencyList.Clear();
+ }
+ }
+ }
+ }
+
+ if( instruction.mRenderTracker && instruction.mFrameBuffer )
+ {
+ // This will create a sync object every frame this render tracker
+ // is alive (though it should be now be created only for
+ // render-once render tasks)
+ instruction.mRenderTracker->CreateSyncObject( mImpl->glSyncAbstraction );
+ instruction.mRenderTracker = nullptr; // Only create once.
+ }
+
+ if ( renderToFbo )
+ {
+ mImpl->currentContext->Flush();