075f30c22215a0dc0337a4745d0306cb2c91938c
[platform/upstream/VK-GL-CTS.git] / framework / platform / android / tcuAndroidRenderActivity.cpp
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 // RenderThread
51
52 RenderThread::RenderThread (NativeActivity& activity)
53         : m_activity            (activity)
54         , m_msgQueue            (MESSAGE_QUEUE_SIZE)
55         , m_threadRunning       (false)
56         , m_inputQueue          (DE_NULL)
57         , m_windowState         (WINDOWSTATE_NOT_CREATED)
58         , m_window                      (DE_NULL)
59         , m_paused                      (false)
60         , m_finish                      (false)
61 {
62 }
63
64 RenderThread::~RenderThread (void)
65 {
66 }
67
68 void RenderThread::start (void)
69 {
70         m_threadRunning = true;
71         Thread::start();
72 }
73
74 void RenderThread::destroy (void)
75 {
76         // Queue finish command
77         enqueue(Message(MESSAGE_FINISH));
78
79         // Wait for thread to terminate
80         join();
81
82         m_threadRunning = false;
83 }
84
85 void RenderThread::enqueue (const Message& message)
86 {
87         // \note Thread must be running or otherwise nobody is going to drain the queue.
88         DE_ASSERT(m_threadRunning);
89         m_msgQueue.pushFront(message);
90 }
91
92 void RenderThread::pause (void)
93 {
94         enqueue(Message(MESSAGE_PAUSE));
95 }
96
97 void RenderThread::resume (void)
98 {
99         enqueue(Message(MESSAGE_RESUME));
100 }
101
102 void RenderThread::sync (void)
103 {
104         de::Semaphore waitSem(0);
105         enqueue(Message(MESSAGE_SYNC, &waitSem));
106         waitSem.decrement();
107 }
108
109 void RenderThread::processMessage (const Message& message)
110 {
111         switch (message.type)
112         {
113                 case MESSAGE_RESUME:    m_paused = false;       break;
114                 case MESSAGE_PAUSE:             m_paused = true;        break;
115                 case MESSAGE_FINISH:    m_finish = true;        break;
116
117                 case MESSAGE_WINDOW_CREATED:
118                         if (m_windowState != WINDOWSTATE_NOT_CREATED && m_windowState != WINDOWSTATE_DESTROYED)
119                                 throw InternalError("Got unexpected onNativeWindowCreated() event from system");
120                         m_windowState   = WINDOWSTATE_NOT_INITIALIZED;
121                         m_window                = message.payload.window;
122                         break;
123
124                 case MESSAGE_WINDOW_RESIZED:
125                         DE_ASSERT(m_window == message.payload.window);
126                         if (m_windowState == WINDOWSTATE_NOT_INITIALIZED)
127                         {
128                                 // Got first resize event, window is ready for use.
129                                 m_windowState = WINDOWSTATE_READY;
130                                 onWindowCreated(message.payload.window);
131                         }
132                         else if (m_windowState == WINDOWSTATE_READY)
133                                 onWindowResized(message.payload.window);
134                         else
135                                 throw InternalError("Got unexpected onNativeWindowResized() event from system");
136                         break;
137
138                 case MESSAGE_WINDOW_DESTROYED:
139                         DE_ASSERT(m_window == message.payload.window);
140                         if (m_windowState != WINDOWSTATE_NOT_INITIALIZED && m_windowState != WINDOWSTATE_READY)
141                                 throw InternalError("Got unexpected onNativeWindowDestroyed() event from system");
142
143                         onWindowDestroyed(message.payload.window);
144                         m_windowState   = WINDOWSTATE_DESTROYED;
145                         m_window                = DE_NULL;
146                         break;
147
148                 case MESSAGE_INPUT_QUEUE_CREATED:
149                         m_inputQueue = message.payload.inputQueue;
150                         break;
151
152                 case MESSAGE_INPUT_QUEUE_DESTROYED:
153                         m_inputQueue = message.payload.inputQueue;
154                         break;
155
156                 case MESSAGE_SYNC:
157                         message.payload.semaphore->increment();
158                         break;
159
160                 default:
161                         throw std::runtime_error("Unknown message type");
162                         break;
163         }
164 }
165
166 void RenderThread::run (void)
167 {
168         // Init state
169         m_windowState   = WINDOWSTATE_NOT_CREATED;
170         m_paused                = true;
171         m_finish                = false;
172
173         try
174         {
175                 while (!m_finish)
176                 {
177                         if (m_paused || m_windowState != WINDOWSTATE_READY)
178                         {
179                                 // Block until we are not paused and window is ready.
180                                 Message msg = m_msgQueue.popBack();
181                                 processMessage(msg);
182                                 continue;
183                         }
184
185                         // Process available commands
186                         {
187                                 Message msg;
188                                 if (m_msgQueue.tryPopBack(msg))
189                                 {
190                                         processMessage(msg);
191                                         continue;
192                                 }
193                         }
194
195                         DE_ASSERT(m_windowState == WINDOWSTATE_READY);
196
197                         // Process input events.
198                         // \todo [2013-05-08 pyry] What if system fills up the input queue before we have window ready?
199                         while (m_inputQueue &&
200                                    AInputQueue_hasEvents(m_inputQueue) > 0)
201                         {
202                                 AInputEvent* event;
203                                 TCU_CHECK(AInputQueue_getEvent(m_inputQueue, &event) >= 0);
204                                 onInputEvent(event);
205                                 AInputQueue_finishEvent(m_inputQueue, event, 1);
206                         }
207
208                         // Everything set up - safe to render.
209                         if (!render())
210                                 break;
211                 }
212
213                 if (m_windowState == WINDOWSTATE_READY)
214                 {
215                         // Clean up window use
216                         onWindowDestroyed(m_window);
217                         m_windowState   = WINDOWSTATE_DESTROYED;
218                         m_window                = DE_NULL;
219                 }
220         }
221         catch (const std::exception& e)
222         {
223                 print("RenderThread: %s\n", e.what());
224         }
225
226         // Tell activity to finish.
227         DBG_PRINT(("RenderThread::run(): done, waiting for FINISH\n"));
228         m_activity.finish();
229
230         // Thread must keep draining message queue until FINISH message is encountered.
231         try
232         {
233                 while (!m_finish)
234                 {
235                         Message msg = m_msgQueue.popBack();
236
237                         // Ignore all but SYNC and FINISH messages.
238                         if (msg.type == MESSAGE_SYNC || msg.type == MESSAGE_FINISH)
239                                 processMessage(msg);
240                 }
241         }
242         catch (const std::exception& e)
243         {
244                 die("RenderThread: %s\n", e.what());
245         }
246
247         DBG_PRINT(("RenderThread::run(): exiting...\n"));
248 }
249
250 // RenderActivity
251
252 RenderActivity::RenderActivity (ANativeActivity* activity)
253         : NativeActivity(activity)
254         , m_thread              (DE_NULL)
255 {
256         DBG_PRINT(("RenderActivity::RenderActivity()"));
257 }
258
259 RenderActivity::~RenderActivity (void)
260 {
261         DBG_PRINT(("RenderActivity::~RenderActivity()"));
262 }
263
264 void RenderActivity::setThread (RenderThread* thread)
265 {
266         DE_ASSERT(!m_thread && thread);
267         m_thread = thread;
268 }
269
270 void RenderActivity::onStart (void)
271 {
272         DBG_PRINT(("RenderActivity::onStart()"));
273
274         // Launch tester thread when activity is created. It will remain in paused state until resume() is called.
275         m_thread->start();
276 }
277
278 void RenderActivity::onResume (void)
279 {
280         DBG_PRINT(("RenderActivity::onResume()"));
281
282         // Resume (or start) test execution
283         m_thread->resume();
284 }
285
286 void RenderActivity::onPause (void)
287 {
288         DBG_PRINT(("RenderActivity::onPause()"));
289
290         // Pause test execution
291         m_thread->pause();
292 }
293
294 void RenderActivity::onStop (void)
295 {
296         DBG_PRINT(("RenderActivity::onStop()"));
297         m_thread->destroy();
298 }
299
300 void RenderActivity::onDestroy (void)
301 {
302         DBG_PRINT(("RenderActivity::onDestroy()"));
303 }
304
305 void RenderActivity::onNativeWindowCreated (ANativeWindow* window)
306 {
307         DBG_PRINT(("RenderActivity::onNativeWindowCreated()"));
308         m_thread->enqueue(Message(MESSAGE_WINDOW_CREATED, window));
309 }
310
311 void RenderActivity::onNativeWindowResized (ANativeWindow* window)
312 {
313         DBG_PRINT(("RenderActivity::onNativeWindowResized()"));
314         m_thread->enqueue(Message(MESSAGE_WINDOW_RESIZED, window));
315 }
316
317 void RenderActivity::onNativeWindowRedrawNeeded (ANativeWindow* window)
318 {
319         DE_UNREF(window);
320 }
321
322 void RenderActivity::onNativeWindowDestroyed (ANativeWindow* window)
323 {
324         DBG_PRINT(("RenderActivity::onNativeWindowDestroyed()"));
325         m_thread->enqueue(Message(MESSAGE_WINDOW_DESTROYED, window));
326         m_thread->sync(); // Block until thread has processed all messages.
327 }
328
329 void RenderActivity::onInputQueueCreated (AInputQueue* queue)
330 {
331         DBG_PRINT(("RenderActivity::onInputQueueCreated()"));
332         m_thread->enqueue(Message(MESSAGE_INPUT_QUEUE_CREATED, queue));
333 }
334
335 void RenderActivity::onInputQueueDestroyed (AInputQueue* queue)
336 {
337         DBG_PRINT(("RenderActivity::onInputQueueDestroyed()"));
338         m_thread->enqueue(Message(MESSAGE_INPUT_QUEUE_DESTROYED, queue));
339         m_thread->sync();
340 }
341
342 } // Android
343 } // tcu