1 // Copyright 2014-2015 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "RenderWindow.h"
16
17 #include "aemu/base/threads/Thread.h"
18 #include "aemu/base/synchronization/MessageChannel.h"
19 #include "host-common/logging.h"
20 #include "FrameBuffer.h"
21 #include "RendererImpl.h"
22
23 #include <stdarg.h>
24 #include <stdio.h>
25 #ifndef _WIN32
26 #include <signal.h>
27 #include <pthread.h>
28 #endif
29
30 namespace gfxstream {
31
32 #define DEBUG 0
33
34 #if DEBUG
35 # define D(...) my_debug(__PRETTY_FUNCTION__, __LINE__, __VA_ARGS__)
36 #else
37 # define D(...) ((void)0)
38 #endif
39
40 namespace {
41
42 #if DEBUG
my_debug(const char * function,int line,const char * format,...)43 void my_debug(const char* function, int line, const char* format, ...) {
44 static ::android::base::Lock mutex;
45 va_list args;
46 va_start(args, format);
47 mutex.lock();
48 fprintf(stderr, "%s:%d:", function, line);
49 vfprintf(stderr, format, args);
50 mutex.unlock();
51 va_end(args);
52 }
53 #endif
54
55 // List of possible commands to send to the render window thread from
56 // the main one.
57 enum Command {
58 CMD_INITIALIZE,
59 CMD_SET_POST_CALLBACK,
60 CMD_SETUP_SUBWINDOW,
61 CMD_REMOVE_SUBWINDOW,
62 CMD_SET_ROTATION,
63 CMD_SET_TRANSLATION,
64 CMD_REPAINT,
65 CMD_HAS_GUEST_POSTED_A_FRAME,
66 CMD_RESET_GUEST_POSTED_A_FRAME,
67 CMD_SET_VSYNC_HZ,
68 CMD_SET_DISPLAY_CONFIGS,
69 CMD_SET_DISPLAY_ACTIVE_CONFIG,
70 CMD_FINALIZE,
71 };
72
73 } // namespace
74
75 // A single message sent from the main thread to the render window thread.
76 // |cmd| determines which fields are valid to read.
77 struct RenderWindowMessage {
78 Command cmd;
79 union {
80 // CMD_INITIALIZE
81 struct {
82 int width;
83 int height;
84 gfxstream::host::FeatureSet* features;
85 bool useSubWindow;
86 bool egl2egl;
87 } init;
88
89 // CMD_SET_POST_CALLBACK
90 struct {
91 Renderer::OnPostCallback on_post;
92 void* on_post_context;
93 uint32_t on_post_displayId;
94 bool use_bgra_readback;
95 } set_post_callback;
96
97 // CMD_SETUP_SUBWINDOW
98 struct {
99 FBNativeWindowType parent;
100 int wx;
101 int wy;
102 int ww;
103 int wh;
104 int fbw;
105 int fbh;
106 float dpr;
107 float rotation;
108 bool deleteExisting;
109 bool hideWindow;
110 } subwindow;
111
112 // CMD_SET_TRANSLATION;
113 struct {
114 float px;
115 float py;
116 } trans;
117
118 // CMD_SET_ROTATION
119 float rotation;
120
121 // CMD_SET_VSYNC_HZ
122 int vsyncHz;
123
124 // CMD_SET_COMPOSE_DIMENSIONS
125 struct {
126 int configId;
127 int width;
128 int height;
129 int dpiX;
130 int dpiY;
131 } displayConfigs;
132
133 int displayActiveConfig;
134
135 // result of operations.
136 bool result;
137 };
138
139 // Process the current message, and updates its |result| field.
140 // Returns true on success, or false on failure.
processgfxstream::RenderWindowMessage141 bool process() const {
142 const RenderWindowMessage& msg = *this;
143 FrameBuffer* fb;
144 bool result = false;
145 switch (msg.cmd) {
146 case CMD_INITIALIZE:
147 GL_LOG("RenderWindow: CMD_INITIALIZE w=%d h=%d",
148 msg.init.width, msg.init.height);
149 result = FrameBuffer::initialize(msg.init.width,
150 msg.init.height,
151 *msg.init.features,
152 msg.init.useSubWindow,
153 msg.init.egl2egl);
154 break;
155
156 case CMD_FINALIZE:
157 GL_LOG("CMD_FINALIZE");
158 D("CMD_FINALIZE\n");
159 // this command may be issued even when frame buffer is not
160 // yet created (e.g. if CMD_INITIALIZE failed),
161 // so make sure we check if it is there before finalizing
162 FrameBuffer::finalize();
163 result = true;
164 break;
165
166 case CMD_SET_POST_CALLBACK:
167 GL_LOG("CMD_SET_POST_CALLBACK");
168 D("CMD_SET_POST_CALLBACK\n");
169 fb = FrameBuffer::getFB();
170 if (fb) {
171 fb->setPostCallback(msg.set_post_callback.on_post,
172 msg.set_post_callback.on_post_context,
173 msg.set_post_callback.on_post_displayId,
174 msg.set_post_callback.use_bgra_readback);
175 result = true;
176 }
177 break;
178
179 case CMD_SETUP_SUBWINDOW:
180 GL_LOG("CMD_SETUP_SUBWINDOW: parent=%p wx=%d wy=%d ww=%d wh=%d fbw=%d fbh=%d dpr=%f rotation=%f",
181 (void*)(intptr_t)msg.subwindow.parent,
182 msg.subwindow.wx,
183 msg.subwindow.wy,
184 msg.subwindow.ww,
185 msg.subwindow.wh,
186 msg.subwindow.fbw,
187 msg.subwindow.fbh,
188 msg.subwindow.dpr,
189 msg.subwindow.rotation);
190 D("CMD_SETUP_SUBWINDOW: parent=%p wx=%d wy=%d ww=%d wh=%d fbw=%d fbh=%d dpr=%f rotation=%f\n",
191 (void*)(intptr_t)msg.subwindow.parent,
192 msg.subwindow.wx,
193 msg.subwindow.wy,
194 msg.subwindow.ww,
195 msg.subwindow.wh,
196 msg.subwindow.fbw,
197 msg.subwindow.fbh,
198 msg.subwindow.dpr,
199 msg.subwindow.rotation);
200 fb = FrameBuffer::getFB();
201 if (fb) {
202 result = FrameBuffer::getFB()->setupSubWindow(
203 msg.subwindow.parent, msg.subwindow.wx, msg.subwindow.wy, msg.subwindow.ww,
204 msg.subwindow.wh, msg.subwindow.fbw, msg.subwindow.fbh, msg.subwindow.dpr,
205 msg.subwindow.rotation, msg.subwindow.deleteExisting,
206 msg.subwindow.hideWindow);
207 }
208 break;
209
210 case CMD_REMOVE_SUBWINDOW:
211 GL_LOG("CMD_REMOVE_SUBWINDOW");
212 D("CMD_REMOVE_SUBWINDOW\n");
213 fb = FrameBuffer::getFB();
214 if (fb) {
215 result = fb->removeSubWindow();
216 }
217 break;
218
219 case CMD_SET_ROTATION:
220 GL_LOG("CMD_SET_ROTATION rotation=%f", msg.rotation);
221 D("CMD_SET_ROTATION rotation=%f\n", msg.rotation);
222 fb = FrameBuffer::getFB();
223 if (fb) {
224 fb->setDisplayRotation(msg.rotation);
225 result = true;
226 }
227 break;
228
229 case CMD_SET_TRANSLATION:
230 GL_LOG("CMD_SET_TRANSLATION translation=%f,%f", msg.trans.px, msg.trans.py);
231 D("CMD_SET_TRANSLATION translation=%f,%f\n", msg.trans.px, msg.trans.py);
232 fb = FrameBuffer::getFB();
233 if (fb) {
234 fb->setDisplayTranslation(msg.trans.px, msg.trans.py);
235 result = true;
236 }
237 break;
238
239 case CMD_REPAINT:
240 GL_LOG("CMD_REPAINT");
241 D("CMD_REPAINT\n");
242 fb = FrameBuffer::getFB();
243 if (fb) {
244 fb->repost();
245 result = true;
246 } else {
247 GL_LOG("CMD_REPAINT: no repost, no FrameBuffer");
248 }
249 break;
250
251 case CMD_HAS_GUEST_POSTED_A_FRAME:
252 GL_LOG("CMD_HAS_GUEST_POSTED_A_FRAME");
253 D("CMD_HAS_GUEST_POSTED_A_FRAME\n");
254 fb = FrameBuffer::getFB();
255 if (fb) {
256 result = fb->hasGuestPostedAFrame();
257 } else {
258 GL_LOG("CMD_HAS_GUEST_POSTED_A_FRAME: no FrameBuffer");
259 }
260 break;
261
262 case CMD_RESET_GUEST_POSTED_A_FRAME:
263 GL_LOG("CMD_RESET_GUEST_POSTED_A_FRAME");
264 D("CMD_RESET_GUEST_POSTED_A_FRAME\n");
265 fb = FrameBuffer::getFB();
266 if (fb) {
267 fb->resetGuestPostedAFrame();
268 result = true;
269 } else {
270 GL_LOG("CMD_RESET_GUEST_POSTED_A_FRAME: no FrameBuffer");
271 }
272 break;
273
274 case CMD_SET_VSYNC_HZ:
275 GL_LOG("CMD_SET_VSYNC_HZ");
276 D("CMD_SET_VSYNC_HZ\n");
277 fb = FrameBuffer::getFB();
278 if (fb) {
279 fb->setVsyncHz(msg.vsyncHz);
280 result = true;
281 } else {
282 GL_LOG("CMD_RESET_GUEST_POSTED_A_FRAME: no FrameBuffer");
283 }
284 break;
285
286 case CMD_SET_DISPLAY_CONFIGS:
287 GL_LOG("CMD_SET_DISPLAY_CONFIGS");
288 D("CMD_SET_DISPLAY_CONFIGS");
289 fb = FrameBuffer::getFB();
290 if (fb) {
291 fb->setDisplayConfigs(msg.displayConfigs.configId,
292 msg.displayConfigs.width,
293 msg.displayConfigs.height,
294 msg.displayConfigs.dpiX,
295 msg.displayConfigs.dpiY);
296 result = true;
297 } else {
298 GL_LOG("CMD_SET_DISPLAY_CONFIGS: no FrameBuffer");
299 }
300 break;
301
302 case CMD_SET_DISPLAY_ACTIVE_CONFIG:
303 GL_LOG("CMD_SET_DISPLAY_ACTIVE_CONFIG");
304 D("CMD_SET_DISPLAY_ACTIVE_CONFIG");
305 fb = FrameBuffer::getFB();
306 if (fb) {
307 fb->setDisplayActiveConfig(msg.displayActiveConfig);
308 result = true;
309 } else {
310 GL_LOG("CMD_SET_DISPLAY_ACTIVE_CONFIG: no FrameBuffer");
311 }
312 break;
313
314 default:
315 ;
316 }
317 return result;
318 }
319 };
320
321 // Simple synchronization structure used to exchange data between the
322 // main and render window threads. Usage is the following:
323 //
324 // The main thread does the following in a loop:
325 //
326 // canWriteCmd.wait()
327 // updates |message| by writing a new |cmd| value and appropriate
328 // parameters.
329 // canReadCmd.signal()
330 // canReadResult.wait()
331 // reads |message.result|
332 // canWriteResult.signal()
333 //
334 // The render window thread will do the following:
335 //
336 // canReadCmd.wait()
337 // reads |message.cmd| and acts upon it.
338 // canWriteResult.wait()
339 // writes |message.result|
340 // canReadResult.signal()
341 // canWriteCmd.signal()
342 //
343 class RenderWindowChannel {
344 public:
RenderWindowChannel()345 RenderWindowChannel() : mIn(), mOut() {}
~RenderWindowChannel()346 ~RenderWindowChannel() {}
347
348 // Send a message from the main thread.
349 // Note that the content of |msg| is copied into the channel.
350 // Returns with the command's result (true or false).
sendMessageAndGetResult(const RenderWindowMessage & msg)351 bool sendMessageAndGetResult(const RenderWindowMessage& msg) {
352 D("msg.cmd=%d\n", msg.cmd);
353 mIn.send(msg);
354 D("waiting for result\n");
355 bool result = false;
356 mOut.receive(&result);
357 D("result=%s\n", result ? "success" : "failure");
358 return result;
359 }
360
361 // Receive a message from the render window thread.
362 // On exit, |*msg| gets a copy of the message. The caller
363 // must always call sendResult() after processing the message.
receiveMessage(RenderWindowMessage * msg)364 void receiveMessage(RenderWindowMessage* msg) {
365 D("entering\n");
366 mIn.receive(msg);
367 D("message cmd=%d\n", msg->cmd);
368 }
369
370 // Send result from the render window thread to the main one.
371 // Must always be called after receiveMessage().
sendResult(bool result)372 void sendResult(bool result) {
373 D("waiting to send result (%s)\n", result ? "success" : "failure");
374 mOut.send(result);
375 D("result sent\n");
376 }
377
378 private:
379 android::base::MessageChannel<RenderWindowMessage, 16U> mIn;
380 android::base::MessageChannel<bool, 16U> mOut;
381 };
382
383 namespace {
384
385 // This class implements the window render thread.
386 // Its purpose is to listen for commands from the main thread in a loop,
387 // process them, then return a boolean result for each one of them.
388 //
389 // The thread ends with a CMD_FINALIZE.
390 //
391 class RenderWindowThread : public android::base::Thread {
392 public:
RenderWindowThread(RenderWindowChannel * channel)393 RenderWindowThread(RenderWindowChannel* channel) : mChannel(channel) {}
394
main()395 virtual intptr_t main() {
396 D("Entering render window thread thread\n");
397 #ifndef _WIN32
398 sigset_t set;
399 sigfillset(&set);
400 pthread_sigmask(SIG_SETMASK, &set, NULL);
401 #endif
402 bool running = true;
403 while (running) {
404 RenderWindowMessage msg = {};
405
406 D("Waiting for message from main thread\n");
407 mChannel->receiveMessage(&msg);
408
409 bool result = msg.process();
410 if (msg.cmd == CMD_FINALIZE) {
411 running = false;
412 }
413
414 D("Sending result (%s) to main thread\n", result ? "success" : "failure");
415 mChannel->sendResult(result);
416 }
417 D("Exiting thread\n");
418 return 0;
419 }
420
421 private:
422 RenderWindowChannel* mChannel;
423 };
424
425 } // namespace
426
RenderWindow(int width,int height,gfxstream::host::FeatureSet features,bool use_thread,bool use_sub_window,bool egl2egl)427 RenderWindow::RenderWindow(int width,
428 int height,
429 gfxstream::host::FeatureSet features,
430 bool use_thread,
431 bool use_sub_window,
432 bool egl2egl)
433 : mRepostThread([this] {
434 while (auto cmd = mRepostCommands.receive()) {
435 if (*cmd == RepostCommand::Sync) {
436 continue;
437 } else if (*cmd == RepostCommand::Repost &&
438 !mPaused) {
439 GL_LOG("Reposting thread dequeueing a CMD_REPAINT");
440 RenderWindowMessage msg = {CMD_REPAINT};
441 (void)msg.process();
442 }
443 }
444 }) {
445 if (use_thread) {
446 mChannel = new RenderWindowChannel();
447 mThread = new RenderWindowThread(mChannel);
448 mThread->start();
449 } else {
450 mRepostThread.start();
451 }
452 RenderWindowMessage msg = {};
453 msg.cmd = CMD_INITIALIZE;
454 msg.init.width = width;
455 msg.init.height = height;
456 msg.init.features = &features;
457 msg.init.useSubWindow = use_sub_window;
458 msg.init.egl2egl = egl2egl;
459 mValid = processMessage(msg);
460 }
461
~RenderWindow()462 RenderWindow::~RenderWindow() {
463 D("Entering\n");
464 removeSubWindow();
465 mRepostCommands.stop();
466 D("Sending CMD_FINALIZE\n");
467 RenderWindowMessage msg = {};
468 msg.cmd = CMD_FINALIZE;
469 (void) processMessage(msg);
470
471 if (useThread()) {
472 mThread->wait(NULL);
473 delete mThread;
474 delete mChannel;
475 } else {
476 mRepostThread.wait();
477 }
478 }
479
setPaused(bool paused)480 void RenderWindow::setPaused(bool paused) {
481 // If pausing, flush commands
482 if (!mPaused && paused) {
483 if (useThread()) {
484 fprintf(stderr,
485 "WARNING: flushMessages unsupported for RenderWindowThread. "
486 "Generic snapshot load might segfault.\n");
487 } else {
488 mRepostCommands.waitForEmpty();
489 }
490 }
491
492 mPaused = paused;
493 }
494
getHardwareStrings(const char ** vendor,const char ** renderer,const char ** version)495 bool RenderWindow::getHardwareStrings(const char** vendor,
496 const char** renderer,
497 const char** version) {
498 D("Entering\n");
499 // TODO(digit): Move this to render window thread.
500 FrameBuffer* fb = FrameBuffer::getFB();
501 if (!fb) {
502 D("No framebuffer!\n");
503 return false;
504 }
505
506 #if GFXSTREAM_ENABLE_HOST_GLES
507 fb->getGLStrings(vendor, renderer, version);
508 D("Exiting vendor=[%s] renderer=[%s] version=[%s]\n",
509 *vendor, *renderer, *version);
510
511 return true;
512 #else
513 return false;
514 #endif
515 }
516
setPostCallback(Renderer::OnPostCallback onPost,void * onPostContext,uint32_t displayId,bool useBgraReadback)517 void RenderWindow::setPostCallback(Renderer::OnPostCallback onPost, void* onPostContext,
518 uint32_t displayId, bool useBgraReadback) {
519 D("Entering\n");
520 RenderWindowMessage msg = {};
521 msg.cmd = CMD_SET_POST_CALLBACK;
522 msg.set_post_callback.on_post = onPost;
523 msg.set_post_callback.on_post_context = onPostContext;
524 msg.set_post_callback.on_post_displayId = displayId;
525 msg.set_post_callback.use_bgra_readback = useBgraReadback;
526 (void) processMessage(msg);
527 D("Exiting\n");
528 }
529
asyncReadbackSupported()530 bool RenderWindow::asyncReadbackSupported() {
531 D("Entering\n");
532 return FrameBuffer::getFB()->asyncReadbackSupported();
533 }
534
getReadPixelsCallback()535 Renderer::ReadPixelsCallback RenderWindow::getReadPixelsCallback() {
536 D("Entering\n");
537 return FrameBuffer::getFB()->getReadPixelsCallback();
538 }
539
addListener(Renderer::FrameBufferChangeEventListener * listener)540 void RenderWindow::addListener(Renderer::FrameBufferChangeEventListener* listener) {
541 FrameBuffer::getFB()->addListener(listener);
542 }
543
removeListener(Renderer::FrameBufferChangeEventListener * listener)544 void RenderWindow::removeListener(Renderer::FrameBufferChangeEventListener* listener) {
545 FrameBuffer::getFB()->removeListener(listener);
546 }
547
getFlushReadPixelPipeline()548 Renderer::FlushReadPixelPipeline RenderWindow::getFlushReadPixelPipeline() {
549 return FrameBuffer::getFB()->getFlushReadPixelPipeline();
550 }
setupSubWindow(FBNativeWindowType window,int wx,int wy,int ww,int wh,int fbw,int fbh,float dpr,float zRot,bool deleteExisting,bool hideWindow)551 bool RenderWindow::setupSubWindow(FBNativeWindowType window,
552 int wx,
553 int wy,
554 int ww,
555 int wh,
556 int fbw,
557 int fbh,
558 float dpr,
559 float zRot,
560 bool deleteExisting,
561 bool hideWindow) {
562 D("Entering mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
563
564 RenderWindowMessage msg = {};
565 msg.cmd = CMD_SETUP_SUBWINDOW;
566 msg.subwindow.parent = window;
567 msg.subwindow.wx = wx;
568 msg.subwindow.wy = wy;
569 msg.subwindow.ww = ww;
570 msg.subwindow.wh = wh;
571 msg.subwindow.fbw = fbw;
572 msg.subwindow.fbh = fbh;
573 msg.subwindow.dpr = dpr;
574 msg.subwindow.rotation = zRot;
575 msg.subwindow.deleteExisting = deleteExisting;
576 msg.subwindow.hideWindow = hideWindow;
577 mHasSubWindow = processMessage(msg);
578
579 D("Exiting mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
580 return mHasSubWindow;
581 }
582
removeSubWindow()583 bool RenderWindow::removeSubWindow() {
584 D("Entering mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
585 if (!mHasSubWindow) {
586 return false;
587 }
588 mHasSubWindow = false;
589 if (!useThread()) {
590 mRepostCommands.send(RepostCommand::Sync);
591 mRepostCommands.waitForEmpty();
592 }
593
594 RenderWindowMessage msg = {};
595 msg.cmd = CMD_REMOVE_SUBWINDOW;
596 bool result = processMessage(msg);
597 D("Exiting result=%s\n", result ? "success" : "failure");
598 return result;
599 }
600
setRotation(float zRot)601 void RenderWindow::setRotation(float zRot) {
602 D("Entering rotation=%f\n", zRot);
603 RenderWindowMessage msg = {};
604 msg.cmd = CMD_SET_ROTATION;
605 msg.rotation = zRot;
606 (void) processMessage(msg);
607 D("Exiting\n");
608 }
609
setTranslation(float px,float py)610 void RenderWindow::setTranslation(float px, float py) {
611 D("Entering translation=%f,%f\n", px, py);
612 RenderWindowMessage msg = {};
613 msg.cmd = CMD_SET_TRANSLATION;
614 msg.trans.px = px;
615 msg.trans.py = py;
616 (void) processMessage(msg);
617 D("Exiting\n");
618 }
619
setScreenMask(int width,int height,const unsigned char * rgbaData)620 void RenderWindow::setScreenMask(int width, int height, const unsigned char* rgbaData) {
621 if (FrameBuffer* fb = FrameBuffer::getFB()) {
622 #if GFXSTREAM_ENABLE_HOST_GLES
623 if (fb->hasEmulationGl()) {
624 fb->getTextureDraw()->setScreenMask(width, height, rgbaData);
625 }
626 #endif
627 }
628 }
629
repaint()630 void RenderWindow::repaint() {
631 D("Entering\n");
632 RenderWindowMessage msg = {};
633 msg.cmd = CMD_REPAINT;
634 (void) processMessage(msg);
635 D("Exiting\n");
636 }
637
hasGuestPostedAFrame()638 bool RenderWindow::hasGuestPostedAFrame() {
639 D("Entering\n");
640 RenderWindowMessage msg = {};
641 msg.cmd = CMD_HAS_GUEST_POSTED_A_FRAME;
642 bool res = processMessage(msg);
643 D("Exiting\n");
644 return res;
645 }
646
resetGuestPostedAFrame()647 void RenderWindow::resetGuestPostedAFrame() {
648 D("Entering\n");
649 RenderWindowMessage msg = {};
650 msg.cmd = CMD_RESET_GUEST_POSTED_A_FRAME;
651 (void) processMessage(msg);
652 D("Exiting\n");
653 }
654
setVsyncHz(int vsyncHz)655 void RenderWindow::setVsyncHz(int vsyncHz) {
656 D("Entering\n");
657 RenderWindowMessage msg = {};
658 msg.cmd = CMD_SET_VSYNC_HZ;
659 msg.vsyncHz = vsyncHz;
660 (void) processMessage(msg);
661 D("Exiting\n");
662 }
663
setDisplayConfigs(int configId,int w,int h,int dpiX,int dpiY)664 void RenderWindow::setDisplayConfigs(int configId, int w, int h,
665 int dpiX, int dpiY) {
666 D("Entering\n");
667 RenderWindowMessage msg = {};
668 msg.cmd = CMD_SET_DISPLAY_CONFIGS;
669 msg.displayConfigs.configId = configId;
670 msg.displayConfigs.width = w;
671 msg.displayConfigs.height= h;
672 msg.displayConfigs.dpiX= dpiX;
673 msg.displayConfigs.dpiY = dpiY;
674 (void) processMessage(msg);
675 D("Exiting\n");
676 }
677
setDisplayActiveConfig(int configId)678 void RenderWindow::setDisplayActiveConfig(int configId) {
679 D("Entering\n");
680 RenderWindowMessage msg = {};
681 msg.cmd = CMD_SET_DISPLAY_ACTIVE_CONFIG;
682 msg.displayActiveConfig = configId;
683 (void) processMessage(msg);
684 D("Exiting\n");
685 }
686
processMessage(const RenderWindowMessage & msg)687 bool RenderWindow::processMessage(const RenderWindowMessage& msg) {
688 if (useThread()) {
689 if (msg.cmd == CMD_REPAINT) {
690 GL_LOG("Sending CMD_REPAINT to render window channel");
691 }
692 return mChannel->sendMessageAndGetResult(msg);
693 } else if (msg.cmd == CMD_REPAINT) {
694 GL_LOG("Sending CMD_REPAINT to reposting thread");
695 mRepostCommands.send(RepostCommand::Repost);
696 return true;
697 } else {
698 return msg.process();
699 }
700 }
701
702 } // namespace gfxstream
703