/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// INTERNAL INCLUDES
#include <base/interfaces/adaptor-internal-services.h>
-#include <base/update-render-synchronization.h>
+#include <base/thread-synchronization.h>
#include <base/environment-options.h>
-
namespace Dali
{
#endif
}
-
-RenderRequest::RenderRequest(RenderRequest::Request type)
-: mRequestType(type)
-{
-}
-
-RenderRequest::Request RenderRequest::GetType()
-{
- return mRequestType;
-}
-
-ReplaceSurfaceRequest::ReplaceSurfaceRequest()
-: RenderRequest(RenderRequest::REPLACE_SURFACE),
- mNewSurface( NULL ),
- mReplaceCompleted(false)
-{
-}
-
-void ReplaceSurfaceRequest::SetSurface(RenderSurface* newSurface)
-{
- mNewSurface = newSurface;
-}
-
-RenderSurface* ReplaceSurfaceRequest::GetSurface()
-{
- return mNewSurface;
-}
-
-void ReplaceSurfaceRequest::ReplaceCompleted()
-{
- mReplaceCompleted = true;
-}
-
-bool ReplaceSurfaceRequest::GetReplaceCompleted()
-{
- return mReplaceCompleted != 0u;
-}
-
-
-RenderThread::RenderThread( UpdateRenderSynchronization& sync,
+RenderThread::RenderThread( ThreadSynchronization& sync,
AdaptorInternalServices& adaptorInterfaces,
const EnvironmentOptions& environmentOptions )
-: mUpdateRenderSync( sync ),
+: mThreadSynchronization( sync ),
mCore( adaptorInterfaces.GetCore() ),
- mGLES( adaptorInterfaces.GetGlesInterface() ),
- mEglFactory( &adaptorInterfaces.GetEGLFactoryInterface()),
- mEGL( NULL ),
mThread( NULL ),
mEnvironmentOptions( environmentOptions ),
- mSurfaceReplaced(false)
+ mRenderHelper( adaptorInterfaces )
{
- // set the initial values before render thread starts
- mSurface = adaptorInterfaces.GetRenderSurfaceInterface();
}
RenderThread::~RenderThread()
{
- DALI_ASSERT_ALWAYS( mThread == NULL && "RenderThread is still alive");
- mEglFactory->Destroy();
}
void RenderThread::Start()
{
DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Start()\n");
- // initialise GL and kick off render thread
- DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" );
-
// create the render thread, initially we are rendering
- mThread = new boost::thread(boost::bind(&RenderThread::Run, this));
+ mThread = new pthread_t();
+ int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
+ DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in RenderThread" );
- mSurface->StartRender();
+ mRenderHelper.Start();
}
void RenderThread::Stop()
{
DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n");
+ mRenderHelper.Stop();
+
// shutdown the render thread and destroy the opengl context
if( mThread )
{
- // Tell surface we have stopped rendering
- mSurface->StopRender();
-
// wait for the thread to finish
- mThread->join();
+ pthread_join(*mThread, NULL);
delete mThread;
mThread = NULL;
bool RenderThread::Run()
{
- // install a function for logging
+ DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run\n");
+
+ // Install a function for logging
mEnvironmentOptions.InstallLogFunction();
- InitializeEgl();
+ mRenderHelper.InitializeEgl();
- bool running( true );
+ // tell core it has a context
+ mCore.ContextCreated();
Dali::Integration::RenderStatus renderStatus;
+ RenderRequest* request = NULL;
- uint64_t currentTime( 0 );
-
- // render loop, we stay inside here when rendering
- while( running )
+ // Render loop, we stay inside here when rendering
+ while( mThreadSynchronization.RenderReady( request ) )
{
- // Sync with update thread and get any outstanding requests from UpdateRenderSynchronization
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderSyncWithUpdate()\n");
- RenderRequest* request = NULL;
- running = mUpdateRenderSync.RenderSyncWithUpdate( request );
+ DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderReady\n");
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - Process requests\n");
+ // Consume any pending events to avoid memory leaks
+ DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - ConsumeEvents\n");
+ mRenderHelper.ConsumeEvents();
- // Consume any pending events
- ConsumeEvents();
-
- bool processRequests = true;
- bool requestProcessed = false;
- while( processRequests && running)
+ // Check if we've got a request from the main thread (e.g. replace surface)
+ if( request )
{
- // Check if we've got any requests from the main thread (e.g. replace surface)
- requestProcessed = ProcessRequest( request );
-
- // perform any pre-render operations
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - PreRender\n");
- bool preRendered = PreRender(); // Returns false if no surface onto which to render
- if( preRendered )
- {
- processRequests = false;
- }
- else
- {
- // Block until new surface... - cleared by ReplaceSurface code in UpdateRenderController
- running = mUpdateRenderSync.RenderSyncWithRequest(request);
- }
+ // Process the request, we should NOT render when we have a request
+ DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - Process requests\n");
+ ProcessRequest( request );
}
-
- if( running )
+ else
{
- // Render
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - Core.Render()\n");
- mCore.Render( renderStatus );
-
- // Notify the update-thread that a render has completed
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 5 - Sync.RenderFinished()\n");
- mUpdateRenderSync.RenderFinished( renderStatus.NeedsUpdate(), requestProcessed );
-
- uint64_t newTime( mUpdateRenderSync.GetTimeMicroseconds() );
-
- // perform any post-render operations
- if ( renderStatus.HasRendered() )
+ // No request to process so we render
+ if( mRenderHelper.PreRender() ) // Returns false if no surface onto which to render
{
- DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 6 - PostRender()\n");
- PostRender( static_cast< unsigned int >(newTime - currentTime) );
+ // Render
+ DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - Core.Render()\n");
+
+ mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::RENDER_START );
+ mCore.Render( renderStatus );
+ mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::RENDER_END );
+
+ // Decrement the count of how far update is ahead of render
+ mThreadSynchronization.RenderFinished();
+
+ // Perform any post-render operations
+ if ( renderStatus.HasRendered() )
+ {
+ DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - PostRender()\n");
+ mRenderHelper.PostRender();
+ }
}
-
- currentTime = newTime;
}
+
+ request = NULL; // Clear the request if it was set, no need to release memory
}
- // shut down egl
- ShutdownEgl();
+ // Inform core of context destruction & shutdown EGL
+ mCore.ContextDestroyed();
+ mRenderHelper.ShutdownEgl();
- // install a function for logging
+ // Uninstall the logging function
mEnvironmentOptions.UnInstallLogFunction();
return true;
}
-void RenderThread::InitializeEgl()
+void RenderThread::ProcessRequest( RenderRequest* request )
{
- mEGL = mEglFactory->Create();
-
- DALI_ASSERT_ALWAYS( mSurface && "NULL surface" );
-
- // initialize egl & OpenGL
- mSurface->InitializeEgl( *mEGL );
-
- // create the OpenGL context
- mEGL->CreateContext();
-
- // create the OpenGL surface
- mSurface->CreateEglSurface( *mEGL );
-
- // Make it current
- mEGL->MakeContextCurrent();
-
- // set the initial sync mode
-
-
- // tell core it has a context
- mCore.ContextCreated();
-
-}
-
-void RenderThread::ConsumeEvents()
-{
- // tell surface to consume any events to avoid memory leaks
- mSurface->ConsumeEvents();
-}
-
-bool RenderThread::ProcessRequest( RenderRequest* request )
-{
- bool processedRequest = false;
-
if( request != NULL )
{
switch(request->GetType())
{
// change the surface
ReplaceSurfaceRequest* replaceSurfaceRequest = static_cast<ReplaceSurfaceRequest*>(request);
- ReplaceSurface( replaceSurfaceRequest->GetSurface() );
+ mRenderHelper.ReplaceSurface( replaceSurfaceRequest->GetSurface() );
replaceSurfaceRequest->ReplaceCompleted();
- processedRequest = true;
+ mThreadSynchronization.RenderInformSurfaceReplaced();
break;
}
}
}
- return processedRequest;
-}
-
-void RenderThread::ReplaceSurface( RenderSurface* newSurface )
-{
- // This is designed for replacing pixmap surfaces, but should work for window as well
- // we need to delete the egl surface and renderable (pixmap / window)
- // Then create a new pixmap/window and new egl surface
- // If the new surface has a different display connection, then the context will be lost
- DALI_ASSERT_ALWAYS( newSurface && "NULL surface" );
-
- bool contextLost = newSurface->ReplaceEGLSurface( *mEGL );
-
- if( contextLost )
- {
- DALI_LOG_WARNING("Context lost\n");
- mCore.ContextDestroyed();
- mCore.ContextCreated();
- }
-
- // if both new and old surface are using the same display, and the display
- // connection was created by Dali, then transfer
- // display owner ship to the new surface.
- mSurface->TransferDisplayOwner( *newSurface );
-
- // use the new surface from now on
- mSurface = newSurface;
- mSurfaceReplaced = true;
-}
-
-
-void RenderThread::ShutdownEgl()
-{
- // inform core of context destruction
- mCore.ContextDestroyed();
-
- // give a chance to destroy the OpenGL surface that created externally
- mSurface->DestroyEglSurface( *mEGL );
-
- // delete the GL context / egl surface
- mEGL->TerminateGles();
-}
-
-bool RenderThread::PreRender()
-{
- bool success = mSurface->PreRender( *mEGL, mGLES );
- if( success )
- {
- mGLES.PreRender();
- }
- return success;
}
-void RenderThread::PostRender( unsigned int timeDelta )
-{
- // Inform the gl implementation that rendering has finished before informing the surface
- mGLES.PostRender(timeDelta);
-
- // Inform the surface that rendering this frame has finished.
- mSurface->PostRender( *mEGL, mGLES, timeDelta, mSurfaceReplaced );
- mSurfaceReplaced = false;
-}
-
-
} // namespace Adaptor
} // namespace Internal