2 * Copyright (c) 2014 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"
23 #include <dali/integration-api/debug.h>
24 #include <base/interfaces/adaptor-internal-services.h>
25 #include <base/update-render-synchronization.h>
26 #include <base/environment-options.h>
40 #if defined(DEBUG_ENABLED)
41 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( UpdateRenderSynchronization& sync,
85 AdaptorInternalServices& adaptorInterfaces,
86 const EnvironmentOptions& environmentOptions )
87 : mUpdateRenderSync( 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();
100 RenderThread::~RenderThread()
102 DALI_ASSERT_ALWAYS( mThread == NULL && "RenderThread is still alive");
103 mEglFactory->Destroy();
106 void RenderThread::Start()
108 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Start()\n");
110 // initialise GL and kick off render thread
111 DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" );
113 // create the render thread, initially we are rendering
114 mThread = new boost::thread(boost::bind(&RenderThread::Run, this));
116 mSurface->StartRender();
119 void RenderThread::Stop()
121 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n");
123 // shutdown the render thread and destroy the opengl context
126 // Tell surface we have stopped rendering
127 mSurface->StopRender();
129 // wait for the thread to finish
137 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
138 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
139 // The following methods are all executed inside render thread !!!
140 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
143 bool RenderThread::Run()
145 // install a function for logging
146 mEnvironmentOptions.InstallLogFunction();
150 bool running( true );
152 Dali::Integration::RenderStatus renderStatus;
154 uint64_t currentTime( 0 );
156 // render loop, we stay inside here when rendering
159 // Sync with update thread and get any outstanding requests from UpdateRenderSynchronization
160 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderSyncWithUpdate()\n");
161 RenderRequest* request = NULL;
162 running = mUpdateRenderSync.RenderSyncWithUpdate( request );
164 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - Process requests\n");
166 // Consume any pending events
169 // Check if we've got any requests from the main thread (e.g. replace surface)
170 bool requestProcessed = ProcessRequest( request );
172 // perform any pre-render operations
173 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - PreRender\n");
174 if( running && PreRender() == true)
177 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - Core.Render()\n");
178 mCore.Render( renderStatus );
180 // Notify the update-thread that a render has completed
181 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 5 - Sync.RenderFinished()\n");
182 mUpdateRenderSync.RenderFinished( renderStatus.NeedsUpdate(), requestProcessed );
184 uint64_t newTime( mUpdateRenderSync.GetTimeMicroseconds() );
186 // perform any post-render operations
187 if ( renderStatus.HasRendered() )
189 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 6 - PostRender()\n");
190 PostRender( static_cast< unsigned int >(newTime - currentTime) );
193 currentTime = newTime;
200 // install a function for logging
201 mEnvironmentOptions.UnInstallLogFunction();
206 void RenderThread::InitializeEgl()
208 mEGL = mEglFactory->Create();
210 DALI_ASSERT_ALWAYS( mSurface && "NULL surface" );
212 // initialize egl & OpenGL
213 mSurface->InitializeEgl( *mEGL );
215 // create the OpenGL context
216 mEGL->CreateContext();
218 // create the OpenGL surface
219 mSurface->CreateEglSurface( *mEGL );
222 mEGL->MakeContextCurrent();
224 // set the initial sync mode
227 // tell core it has a context
228 mCore.ContextCreated();
232 void RenderThread::ConsumeEvents()
234 // tell surface to consume any events to avoid memory leaks
235 mSurface->ConsumeEvents();
238 bool RenderThread::ProcessRequest( RenderRequest* request )
240 bool processedRequest = false;
242 if( request != NULL )
244 switch(request->GetType())
246 case RenderRequest::REPLACE_SURFACE:
248 // change the surface
249 ReplaceSurfaceRequest* replaceSurfaceRequest = static_cast<ReplaceSurfaceRequest*>(request);
250 ReplaceSurface( replaceSurfaceRequest->GetSurface() );
251 replaceSurfaceRequest->ReplaceCompleted();
252 processedRequest = true;
257 return processedRequest;
260 void RenderThread::ReplaceSurface( RenderSurface* newSurface )
262 // This is designed for replacing pixmap surfaces, but should work for window as well
263 // we need to delete the egl surface and renderable (pixmap / window)
264 // Then create a new pixmap/window and new egl surface
265 // If the new surface has a different display connection, then the context will be lost
266 DALI_ASSERT_ALWAYS( newSurface && "NULL surface" );
268 bool contextLost = newSurface->ReplaceEGLSurface( *mEGL );
272 DALI_LOG_WARNING("Context lost\n");
273 mCore.ContextDestroyed();
274 mCore.ContextCreated();
277 // if both new and old surface are using the same display, and the display
278 // connection was created by Dali, then transfer
279 // display owner ship to the new surface.
280 mSurface->TransferDisplayOwner( *newSurface );
282 // use the new surface from now on
283 mSurface = newSurface;
284 mSurfaceReplaced = true;
288 void RenderThread::ShutdownEgl()
290 // inform core of context destruction
291 mCore.ContextDestroyed();
293 // give a chance to destroy the OpenGL surface that created externally
294 mSurface->DestroyEglSurface( *mEGL );
296 // delete the GL context / egl surface
297 mEGL->TerminateGles();
300 bool RenderThread::PreRender()
302 bool success = mSurface->PreRender( *mEGL, mGLES );
310 void RenderThread::PostRender( unsigned int timeDelta )
312 // Inform the gl implementation that rendering has finished before informing the surface
313 mGLES.PostRender(timeDelta);
315 // Inform the surface that rendering this frame has finished.
316 mSurface->PostRender( *mEGL, mGLES, timeDelta, mSurfaceReplaced );
317 mSurfaceReplaced = false;
321 } // namespace Adaptor
323 } // namespace Internal