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