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"
22 #include <dali/integration-api/debug.h>
25 #include <base/interfaces/adaptor-internal-services.h>
26 #include <base/update-render-synchronization.h>
27 #include <base/environment-options.h>
41 #if defined(DEBUG_ENABLED)
42 Integration::Log::Filter* gRenderLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_RENDER_THREAD");
47 RenderRequest::RenderRequest(RenderRequest::Request type)
52 RenderRequest::Request RenderRequest::GetType()
57 ReplaceSurfaceRequest::ReplaceSurfaceRequest()
58 : RenderRequest(RenderRequest::REPLACE_SURFACE),
60 mReplaceCompleted(false)
64 void ReplaceSurfaceRequest::SetSurface(RenderSurface* newSurface)
66 mNewSurface = newSurface;
69 RenderSurface* ReplaceSurfaceRequest::GetSurface()
74 void ReplaceSurfaceRequest::ReplaceCompleted()
76 mReplaceCompleted = true;
79 bool ReplaceSurfaceRequest::GetReplaceCompleted()
81 return mReplaceCompleted != 0u;
85 RenderThread::RenderThread( UpdateRenderSynchronization& sync,
86 AdaptorInternalServices& adaptorInterfaces,
87 const EnvironmentOptions& environmentOptions )
88 : mUpdateRenderSync( sync ),
89 mCore( adaptorInterfaces.GetCore() ),
90 mGLES( adaptorInterfaces.GetGlesInterface() ),
91 mEglFactory( &adaptorInterfaces.GetEGLFactoryInterface()),
94 mEnvironmentOptions( environmentOptions ),
95 mSurfaceReplaced(false)
97 // set the initial values before render thread starts
98 mSurface = adaptorInterfaces.GetRenderSurfaceInterface();
101 RenderThread::~RenderThread()
103 DALI_ASSERT_ALWAYS( mThread == NULL && "RenderThread is still alive");
104 mEglFactory->Destroy();
107 void RenderThread::Start()
109 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Start()\n");
111 // initialise GL and kick off render thread
112 DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" );
114 // create the render thread, initially we are rendering
115 mThread = new boost::thread(boost::bind(&RenderThread::Run, this));
117 mSurface->StartRender();
120 void RenderThread::Stop()
122 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n");
124 // shutdown the render thread and destroy the opengl context
127 // Tell surface we have stopped rendering
128 mSurface->StopRender();
130 // wait for the thread to finish
138 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
139 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
140 // The following methods are all executed inside render thread !!!
141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
142 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
144 bool RenderThread::Run()
146 // install a function for logging
147 mEnvironmentOptions.InstallLogFunction();
151 bool running( true );
153 Dali::Integration::RenderStatus renderStatus;
155 uint64_t currentTime( 0 );
157 // render loop, we stay inside here when rendering
160 // Sync with update thread and get any outstanding requests from UpdateRenderSynchronization
161 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderSyncWithUpdate()\n");
162 RenderRequest* request = NULL;
163 running = mUpdateRenderSync.RenderSyncWithUpdate( request );
165 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - Process requests\n");
167 // Consume any pending events
170 bool processRequests = true;
171 bool requestProcessed = false;
172 while( processRequests && running)
174 // Check if we've got any requests from the main thread (e.g. replace surface)
175 requestProcessed = ProcessRequest( request );
177 // perform any pre-render operations
178 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - PreRender\n");
179 bool preRendered = PreRender(); // Returns false if no surface onto which to render
182 processRequests = false;
186 // Block until new surface... - cleared by ReplaceSurface code in UpdateRenderController
187 running = mUpdateRenderSync.RenderSyncWithRequest(request);
194 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - Core.Render()\n");
195 mCore.Render( renderStatus );
197 // Notify the update-thread that a render has completed
198 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 5 - Sync.RenderFinished()\n");
199 mUpdateRenderSync.RenderFinished( renderStatus.NeedsUpdate(), requestProcessed );
201 uint64_t newTime( mUpdateRenderSync.GetTimeMicroseconds() );
203 // perform any post-render operations
204 if ( renderStatus.HasRendered() )
206 DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 6 - PostRender()\n");
207 PostRender( static_cast< unsigned int >(newTime - currentTime) );
210 currentTime = newTime;
217 // install a function for logging
218 mEnvironmentOptions.UnInstallLogFunction();
223 void RenderThread::InitializeEgl()
225 mEGL = mEglFactory->Create();
227 DALI_ASSERT_ALWAYS( mSurface && "NULL surface" );
229 // initialize egl & OpenGL
230 mSurface->InitializeEgl( *mEGL );
232 // create the OpenGL context
233 mEGL->CreateContext();
235 // create the OpenGL surface
236 mSurface->CreateEglSurface( *mEGL );
239 mEGL->MakeContextCurrent();
241 // set the initial sync mode
244 // tell core it has a context
245 mCore.ContextCreated();
249 void RenderThread::ConsumeEvents()
251 // tell surface to consume any events to avoid memory leaks
252 mSurface->ConsumeEvents();
255 bool RenderThread::ProcessRequest( RenderRequest* request )
257 bool processedRequest = false;
259 if( request != NULL )
261 switch(request->GetType())
263 case RenderRequest::REPLACE_SURFACE:
265 // change the surface
266 ReplaceSurfaceRequest* replaceSurfaceRequest = static_cast<ReplaceSurfaceRequest*>(request);
267 ReplaceSurface( replaceSurfaceRequest->GetSurface() );
268 replaceSurfaceRequest->ReplaceCompleted();
269 processedRequest = true;
274 return processedRequest;
277 void RenderThread::ReplaceSurface( RenderSurface* newSurface )
279 // This is designed for replacing pixmap surfaces, but should work for window as well
280 // we need to delete the egl surface and renderable (pixmap / window)
281 // Then create a new pixmap/window and new egl surface
282 // If the new surface has a different display connection, then the context will be lost
283 DALI_ASSERT_ALWAYS( newSurface && "NULL surface" );
285 bool contextLost = newSurface->ReplaceEGLSurface( *mEGL );
289 DALI_LOG_WARNING("Context lost\n");
290 mCore.ContextDestroyed();
291 mCore.ContextCreated();
294 // if both new and old surface are using the same display, and the display
295 // connection was created by Dali, then transfer
296 // display owner ship to the new surface.
297 mSurface->TransferDisplayOwner( *newSurface );
299 // use the new surface from now on
300 mSurface = newSurface;
301 mSurfaceReplaced = true;
305 void RenderThread::ShutdownEgl()
307 // inform core of context destruction
308 mCore.ContextDestroyed();
310 // give a chance to destroy the OpenGL surface that created externally
311 mSurface->DestroyEglSurface( *mEGL );
313 // delete the GL context / egl surface
314 mEGL->TerminateGles();
317 bool RenderThread::PreRender()
319 bool success = mSurface->PreRender( *mEGL, mGLES );
327 void RenderThread::PostRender( unsigned int timeDelta )
329 // Inform the gl implementation that rendering has finished before informing the surface
330 mGLES.PostRender(timeDelta);
332 // Inform the surface that rendering this frame has finished.
333 mSurface->PostRender( *mEGL, mGLES, timeDelta, mSurfaceReplaced );
334 mSurfaceReplaced = false;
338 } // namespace Adaptor
340 } // namespace Internal