1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief RenderActivity base class.
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuAndroidRenderActivity.hpp"
25 #include "deSemaphore.hpp"
26
27 #include <android/window.h>
28
29 #include <string>
30 #include <stdlib.h>
31
32 using std::string;
33
34 #if defined(DE_DEBUG)
35 # define DBG_PRINT(X) print X
36 #else
37 # define DBG_PRINT(X)
38 #endif
39
40 namespace tcu
41 {
42 namespace Android
43 {
44
45 enum
46 {
47 MESSAGE_QUEUE_SIZE = 8 //!< Length of RenderThread message queue.
48 };
49
50 #if defined(DE_DEBUG)
getMessageTypeName(MessageType type)51 static const char* getMessageTypeName (MessageType type)
52 {
53 static const char* s_names[] =
54 {
55 "RESUME",
56 "PAUSE",
57 "FINISH",
58 "WINDOW_CREATED",
59 "WINDOW_RESIZED",
60 "WINDOW_DESTROYED",
61 "INPUT_QUEUE_CREATED",
62 "INPUT_QUEUE_DESTROYED",
63 "SYNC"
64 };
65 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == MESSAGETYPE_LAST);
66 return s_names[type];
67 }
68 #endif
69
70 // RenderThread
71
RenderThread(NativeActivity & activity)72 RenderThread::RenderThread (NativeActivity& activity)
73 : m_activity (activity)
74 , m_msgQueue (MESSAGE_QUEUE_SIZE)
75 , m_threadRunning (false)
76 , m_inputQueue (DE_NULL)
77 , m_windowState (WINDOWSTATE_NOT_CREATED)
78 , m_window (DE_NULL)
79 , m_paused (false)
80 , m_finish (false)
81 {
82 }
83
~RenderThread(void)84 RenderThread::~RenderThread (void)
85 {
86 }
87
start(void)88 void RenderThread::start (void)
89 {
90 m_threadRunning = true;
91 Thread::start();
92 }
93
stop(void)94 void RenderThread::stop (void)
95 {
96 // Queue finish command
97 enqueue(Message(MESSAGE_FINISH));
98
99 // Wait for thread to terminate
100 join();
101
102 m_threadRunning = false;
103 }
104
enqueue(const Message & message)105 void RenderThread::enqueue (const Message& message)
106 {
107 // \note Thread must be running or otherwise nobody is going to drain the queue.
108 DE_ASSERT(m_threadRunning);
109 m_msgQueue.pushFront(message);
110 }
111
pause(void)112 void RenderThread::pause (void)
113 {
114 enqueue(Message(MESSAGE_PAUSE));
115 }
116
resume(void)117 void RenderThread::resume (void)
118 {
119 enqueue(Message(MESSAGE_RESUME));
120 }
121
sync(void)122 void RenderThread::sync (void)
123 {
124 de::Semaphore waitSem(0);
125 enqueue(Message(MESSAGE_SYNC, &waitSem));
126 waitSem.decrement();
127 }
128
processMessage(const Message & message)129 void RenderThread::processMessage (const Message& message)
130 {
131 DBG_PRINT(("RenderThread::processMessage(): message = { %s, %p }\n", getMessageTypeName(message.type), message.payload.window));
132
133 switch (message.type)
134 {
135 case MESSAGE_RESUME: m_paused = false; break;
136 case MESSAGE_PAUSE: m_paused = true; break;
137 case MESSAGE_FINISH: m_finish = true; break;
138
139 // \note While Platform / WindowRegistry are currently multi-window -capable,
140 // the fact that platform gives us windows too late / at unexpected times
141 // forces us to do some sanity checking and limit system to one window here.
142 case MESSAGE_WINDOW_CREATED:
143 if (m_windowState != WINDOWSTATE_NOT_CREATED && m_windowState != WINDOWSTATE_DESTROYED)
144 throw InternalError("Got unexpected onNativeWindowCreated() event from system");
145
146 m_windowState = WINDOWSTATE_NOT_INITIALIZED;
147 m_window = message.payload.window;
148 break;
149
150 case MESSAGE_WINDOW_RESIZED:
151 if (m_window != message.payload.window)
152 throw InternalError("Got onNativeWindowResized() event targeting different window");
153
154 if (m_windowState == WINDOWSTATE_NOT_INITIALIZED)
155 {
156 // Got first resize event, window is ready for use.
157 m_windowState = WINDOWSTATE_READY;
158 onWindowCreated(message.payload.window);
159 }
160 else if (m_windowState == WINDOWSTATE_READY)
161 onWindowResized(message.payload.window);
162 else
163 throw InternalError("Got unexpected onNativeWindowResized() event from system");
164
165 break;
166
167 case MESSAGE_WINDOW_DESTROYED:
168 if (m_window != message.payload.window)
169 throw InternalError("Got onNativeWindowDestroyed() event targeting different window");
170
171 if (m_windowState != WINDOWSTATE_NOT_INITIALIZED && m_windowState != WINDOWSTATE_READY)
172 throw InternalError("Got unexpected onNativeWindowDestroyed() event from system");
173
174 if (m_windowState == WINDOWSTATE_READY)
175 onWindowDestroyed(message.payload.window);
176
177 m_windowState = WINDOWSTATE_DESTROYED;
178 m_window = DE_NULL;
179 break;
180
181 case MESSAGE_INPUT_QUEUE_CREATED:
182 m_inputQueue = message.payload.inputQueue;
183 break;
184
185 case MESSAGE_INPUT_QUEUE_DESTROYED:
186 m_inputQueue = message.payload.inputQueue;
187 break;
188
189 case MESSAGE_SYNC:
190 message.payload.semaphore->increment();
191 break;
192
193 default:
194 throw std::runtime_error("Unknown message type");
195 break;
196 }
197 }
198
run(void)199 void RenderThread::run (void)
200 {
201 // Init state
202 m_windowState = WINDOWSTATE_NOT_CREATED;
203 m_paused = true;
204 m_finish = false;
205
206 try
207 {
208 while (!m_finish)
209 {
210 if (m_paused || m_windowState != WINDOWSTATE_READY)
211 {
212 // Block until we are not paused and window is ready.
213 Message msg = m_msgQueue.popBack();
214 processMessage(msg);
215 continue;
216 }
217
218 // Process available commands
219 {
220 Message msg;
221 if (m_msgQueue.tryPopBack(msg))
222 {
223 processMessage(msg);
224 continue;
225 }
226 }
227
228 DE_ASSERT(m_windowState == WINDOWSTATE_READY);
229
230 // Process input events.
231 // \todo [2013-05-08 pyry] What if system fills up the input queue before we have window ready?
232 while (m_inputQueue &&
233 AInputQueue_hasEvents(m_inputQueue) > 0)
234 {
235 AInputEvent* event;
236 TCU_CHECK(AInputQueue_getEvent(m_inputQueue, &event) >= 0);
237 onInputEvent(event);
238 AInputQueue_finishEvent(m_inputQueue, event, 1);
239 }
240
241 // Everything set up - safe to render.
242 if (!render())
243 {
244 DBG_PRINT(("RenderThread::run(): render\n"));
245 break;
246 }
247 }
248 }
249 catch (const std::exception& e)
250 {
251 print("RenderThread: %s\n", e.what());
252 }
253
254 // Tell activity to finish.
255 DBG_PRINT(("RenderThread::run(): done, waiting for FINISH\n"));
256 m_activity.finish();
257
258 // Thread must keep draining message queue until FINISH message is encountered.
259 try
260 {
261 while (!m_finish)
262 {
263 Message msg = m_msgQueue.popBack();
264
265 // Ignore all but SYNC and FINISH messages.
266 if (msg.type == MESSAGE_SYNC || msg.type == MESSAGE_FINISH)
267 processMessage(msg);
268 }
269 }
270 catch (const std::exception& e)
271 {
272 die("RenderThread: %s\n", e.what());
273 }
274
275 DBG_PRINT(("RenderThread::run(): exiting...\n"));
276 }
277
278 // RenderActivity
279
RenderActivity(ANativeActivity * activity)280 RenderActivity::RenderActivity (ANativeActivity* activity)
281 : NativeActivity(activity)
282 , m_thread (DE_NULL)
283 {
284 DBG_PRINT(("RenderActivity::RenderActivity()"));
285 }
286
~RenderActivity(void)287 RenderActivity::~RenderActivity (void)
288 {
289 DBG_PRINT(("RenderActivity::~RenderActivity()"));
290 }
291
setThread(RenderThread * thread)292 void RenderActivity::setThread (RenderThread* thread)
293 {
294 m_thread = thread;
295 }
296
onStart(void)297 void RenderActivity::onStart (void)
298 {
299 DBG_PRINT(("RenderActivity::onStart()"));
300 }
301
onResume(void)302 void RenderActivity::onResume (void)
303 {
304 DBG_PRINT(("RenderActivity::onResume()"));
305
306 // Resume (or start) test execution
307 m_thread->resume();
308 }
309
onPause(void)310 void RenderActivity::onPause (void)
311 {
312 DBG_PRINT(("RenderActivity::onPause()"));
313
314 // Pause test execution
315 m_thread->pause();
316 }
317
onStop(void)318 void RenderActivity::onStop (void)
319 {
320 DBG_PRINT(("RenderActivity::onStop()"));
321 }
322
onDestroy(void)323 void RenderActivity::onDestroy (void)
324 {
325 DBG_PRINT(("RenderActivity::onDestroy()"));
326 }
327
onNativeWindowCreated(ANativeWindow * window)328 void RenderActivity::onNativeWindowCreated (ANativeWindow* window)
329 {
330 DBG_PRINT(("RenderActivity::onNativeWindowCreated()"));
331 m_thread->enqueue(Message(MESSAGE_WINDOW_CREATED, window));
332 }
333
onNativeWindowResized(ANativeWindow * window)334 void RenderActivity::onNativeWindowResized (ANativeWindow* window)
335 {
336 DBG_PRINT(("RenderActivity::onNativeWindowResized()"));
337 m_thread->enqueue(Message(MESSAGE_WINDOW_RESIZED, window));
338 }
339
onNativeWindowRedrawNeeded(ANativeWindow * window)340 void RenderActivity::onNativeWindowRedrawNeeded (ANativeWindow* window)
341 {
342 DE_UNREF(window);
343 }
344
onNativeWindowDestroyed(ANativeWindow * window)345 void RenderActivity::onNativeWindowDestroyed (ANativeWindow* window)
346 {
347 DBG_PRINT(("RenderActivity::onNativeWindowDestroyed()"));
348 m_thread->enqueue(Message(MESSAGE_WINDOW_DESTROYED, window));
349 m_thread->sync(); // Block until thread has processed all messages.
350 }
351
onInputQueueCreated(AInputQueue * queue)352 void RenderActivity::onInputQueueCreated (AInputQueue* queue)
353 {
354 DBG_PRINT(("RenderActivity::onInputQueueCreated()"));
355 m_thread->enqueue(Message(MESSAGE_INPUT_QUEUE_CREATED, queue));
356 }
357
onInputQueueDestroyed(AInputQueue * queue)358 void RenderActivity::onInputQueueDestroyed (AInputQueue* queue)
359 {
360 DBG_PRINT(("RenderActivity::onInputQueueDestroyed()"));
361 m_thread->enqueue(Message(MESSAGE_INPUT_QUEUE_DESTROYED, queue));
362 m_thread->sync();
363 }
364
365 } // Android
366 } // tcu
367