2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "render-thread.h"
22 #include <dali/integration-api/debug.h>
25 #include <base/interfaces/adaptor-internal-services.h>
26 #include <base/thread-synchronization.h>
27 #include <base/environment-options.h>
28 #include <base/display-connection.h>
41 #if defined(DEBUG_ENABLED)
42 Integration::Log::Filter* gRenderLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_RENDER_THREAD");
46 RenderRequest::RenderRequest(RenderRequest::Request type)
51 RenderRequest::Request RenderRequest::GetType()
56 ReplaceSurfaceRequest::ReplaceSurfaceRequest()
57 : RenderRequest(RenderRequest::REPLACE_SURFACE),
59 mReplaceCompleted(false)
63 void ReplaceSurfaceRequest::SetSurface(RenderSurface* newSurface)
65 mNewSurface = newSurface;
68 RenderSurface* ReplaceSurfaceRequest::GetSurface()
73 void ReplaceSurfaceRequest::ReplaceCompleted()
75 mReplaceCompleted = true;
78 bool ReplaceSurfaceRequest::GetReplaceCompleted()
80 return mReplaceCompleted != 0u;
84 RenderThread::RenderThread( ThreadSynchronization& sync,
85 AdaptorInternalServices& adaptorInterfaces,
86 const EnvironmentOptions& environmentOptions )
87 : mThreadSynchronization( sync ),
88 mCore( adaptorInterfaces.GetCore() ),
89 mGLES( adaptorInterfaces.GetGlesInterface() ),
90 mEglFactory( &adaptorInterfaces.GetEGLFactoryInterface()),
93 mEnvironmentOptions( environmentOptions ),
94 mSurfaceReplaced(false)
96 // set the initial values before render thread starts
97 mSurface = adaptorInterfaces.GetRenderSurfaceInterface();
99 mDisplayConnection = Dali::DisplayConnection::New();
102 RenderThread::~RenderThread()
104 if (mDisplayConnection)
106 delete mDisplayConnection;
107 mDisplayConnection = NULL;
110 DALI_ASSERT_ALWAYS( mThread == NULL && "RenderThread is still alive");
111 mEglFactory->Destroy();
114 void RenderThread::Start()
116 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Start()\n");
118 // initialise GL and kick off render thread
119 DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" );
121 // create the render thread, initially we are rendering
122 mThread = new pthread_t();
123 int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
124 DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in RenderThread" );
128 mSurface->StartRender();
132 void RenderThread::Stop()
134 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n");
138 // Tell surface we have stopped rendering
139 mSurface->StopRender();
141 // The surface will be destroyed soon; this pointer will become invalid
145 // shutdown the render thread and destroy the opengl context
148 // wait for the thread to finish
149 pthread_join(*mThread, NULL);
156 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
157 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
158 // The following methods are all executed inside render thread !!!
159 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
160 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
162 bool RenderThread::Run()
164 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run\n");
166 // Install a function for logging
167 mEnvironmentOptions.InstallLogFunction();
171 Dali::Integration::RenderStatus renderStatus;
172 RenderRequest* request = NULL;
174 // Render loop, we stay inside here when rendering
175 while( mThreadSynchronization.RenderReady( request ) )
177 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderReady\n");
179 // Consume any pending events to avoid memory leaks
180 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - ConsumeEvents\n");
181 mDisplayConnection->ConsumeEvents();
183 // Check if we've got a request from the main thread (e.g. replace surface)
186 // Process the request, we should NOT render when we have a request
187 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - Process requests\n");
188 ProcessRequest( request );
192 // No request to process so we render
193 if( PreRender() ) // Returns false if no surface onto which to render
196 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - Core.Render()\n");
198 mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::RENDER_START );
199 mCore.Render( renderStatus );
200 mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::RENDER_END );
202 // Decrement the count of how far update is ahead of render
203 mThreadSynchronization.RenderFinished();
205 // Perform any post-render operations
206 if ( renderStatus.HasRendered() )
208 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - PostRender()\n");
214 request = NULL; // Clear the request if it was set, no need to release memory
220 // Uninstall the logging function
221 mEnvironmentOptions.UnInstallLogFunction();
226 void RenderThread::InitializeEgl()
228 mEGL = mEglFactory->Create();
230 DALI_ASSERT_ALWAYS( mSurface && "NULL surface" );
232 // initialize egl & OpenGL
233 mDisplayConnection->InitializeEgl( *mEGL );
234 mSurface->InitializeEgl( *mEGL );
236 // create the OpenGL context
237 mEGL->CreateContext();
239 // create the OpenGL surface
240 mSurface->CreateEglSurface(*mEGL);
243 mEGL->MakeContextCurrent();
245 // set the initial sync mode
247 // tell core it has a context
248 mCore.ContextCreated();
252 void RenderThread::ProcessRequest( RenderRequest* request )
254 if( request != NULL )
256 switch(request->GetType())
258 case RenderRequest::REPLACE_SURFACE:
260 // change the surface
261 ReplaceSurfaceRequest* replaceSurfaceRequest = static_cast<ReplaceSurfaceRequest*>(request);
262 ReplaceSurface( replaceSurfaceRequest->GetSurface() );
263 replaceSurfaceRequest->ReplaceCompleted();
264 mThreadSynchronization.RenderInformSurfaceReplaced();
271 void RenderThread::ReplaceSurface( RenderSurface* newSurface )
273 // This is designed for replacing pixmap surfaces, but should work for window as well
274 // we need to delete the egl surface and renderable (pixmap / window)
275 // Then create a new pixmap/window and new egl surface
276 // If the new surface has a different display connection, then the context will be lost
277 DALI_ASSERT_ALWAYS(newSurface && "NULL surface");
279 mDisplayConnection->InitializeEgl(*mEGL);
281 newSurface->ReplaceEGLSurface(*mEGL);
283 // use the new surface from now on
284 mSurface = newSurface;
285 mSurfaceReplaced = true;
288 void RenderThread::ShutdownEgl()
290 // inform core of context destruction
291 mCore.ContextDestroyed();
295 // give a chance to destroy the OpenGL surface that created externally
296 mSurface->DestroyEglSurface( *mEGL );
299 // delete the GL context / egl surface
300 mEGL->TerminateGles();
303 bool RenderThread::PreRender()
305 bool success( false );
308 success = mSurface->PreRender( *mEGL, mGLES );
318 void RenderThread::PostRender()
320 // Inform the gl implementation that rendering has finished before informing the surface
325 // Inform the surface that rendering this frame has finished.
326 mSurface->PostRender( *mEGL, mGLES, mDisplayConnection, mSurfaceReplaced );
328 mSurfaceReplaced = false;
331 } // namespace Adaptor
333 } // namespace Internal