• 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     RenderWindowMessage msg = {};
450     msg.cmd = CMD_INITIALIZE;
451     msg.init.width = width;
452     msg.init.height = height;
453     msg.init.useSubWindow = use_sub_window;
454     msg.init.egl2egl = egl2egl;
455     mValid = processMessage(msg);
456 }
457 
~RenderWindow()458 RenderWindow::~RenderWindow() {
459     D("Entering\n");
460     removeSubWindow();
461     mRepostCommands.stop();
462     D("Sending CMD_FINALIZE\n");
463     RenderWindowMessage msg = {};
464     msg.cmd = CMD_FINALIZE;
465     (void) processMessage(msg);
466 
467     if (useThread()) {
468         mThread->wait(NULL);
469         delete mThread;
470         delete mChannel;
471     } else {
472         mRepostThread.wait();
473     }
474 }
475 
setPaused(bool paused)476 void RenderWindow::setPaused(bool paused) {
477     // If pausing, flush commands
478     if (!mPaused && paused) {
479         if (useThread()) {
480             fprintf(stderr,
481                     "WARNING: flushMessages unsupported for RenderWindowThread. "
482                     "Generic snapshot load might segfault.\n");
483         } else {
484             mRepostCommands.waitForEmpty();
485         }
486     }
487 
488     mPaused = paused;
489 }
490 
getHardwareStrings(const char ** vendor,const char ** renderer,const char ** version)491 bool RenderWindow::getHardwareStrings(const char** vendor,
492                                       const char** renderer,
493                                       const char** version) {
494     D("Entering\n");
495     // TODO(digit): Move this to render window thread.
496     FrameBuffer* fb = FrameBuffer::getFB();
497     if (!fb) {
498         D("No framebuffer!\n");
499         return false;
500     }
501 
502 #if GFXSTREAM_ENABLE_HOST_GLES
503     fb->getGLStrings(vendor, renderer, version);
504     D("Exiting vendor=[%s] renderer=[%s] version=[%s]\n",
505       *vendor, *renderer, *version);
506 
507     return true;
508 #else
509     return false;
510 #endif
511 }
512 
setPostCallback(Renderer::OnPostCallback onPost,void * onPostContext,uint32_t displayId,bool useBgraReadback)513 void RenderWindow::setPostCallback(Renderer::OnPostCallback onPost, void* onPostContext,
514                                    uint32_t displayId, bool useBgraReadback) {
515     D("Entering\n");
516     RenderWindowMessage msg = {};
517     msg.cmd = CMD_SET_POST_CALLBACK;
518     msg.set_post_callback.on_post = onPost;
519     msg.set_post_callback.on_post_context = onPostContext;
520     msg.set_post_callback.on_post_displayId = displayId;
521     msg.set_post_callback.use_bgra_readback = useBgraReadback;
522     (void) processMessage(msg);
523     D("Exiting\n");
524 }
525 
asyncReadbackSupported()526 bool RenderWindow::asyncReadbackSupported() {
527     D("Entering\n");
528     return FrameBuffer::getFB()->asyncReadbackSupported();
529 }
530 
getReadPixelsCallback()531 Renderer::ReadPixelsCallback RenderWindow::getReadPixelsCallback() {
532     D("Entering\n");
533     return FrameBuffer::getFB()->getReadPixelsCallback();
534 }
535 
addListener(Renderer::FrameBufferChangeEventListener * listener)536 void RenderWindow::addListener(Renderer::FrameBufferChangeEventListener* listener) {
537     FrameBuffer::getFB()->addListener(listener);
538 }
539 
removeListener(Renderer::FrameBufferChangeEventListener * listener)540 void RenderWindow::removeListener(Renderer::FrameBufferChangeEventListener* listener) {
541     FrameBuffer::getFB()->removeListener(listener);
542 }
543 
getFlushReadPixelPipeline()544 Renderer::FlushReadPixelPipeline RenderWindow::getFlushReadPixelPipeline() {
545     return FrameBuffer::getFB()->getFlushReadPixelPipeline();
546 }
setupSubWindow(FBNativeWindowType window,int wx,int wy,int ww,int wh,int fbw,int fbh,float dpr,float zRot,bool deleteExisting,bool hideWindow)547 bool RenderWindow::setupSubWindow(FBNativeWindowType window,
548                                   int wx,
549                                   int wy,
550                                   int ww,
551                                   int wh,
552                                   int fbw,
553                                   int fbh,
554                                   float dpr,
555                                   float zRot,
556                                   bool deleteExisting,
557                                   bool hideWindow) {
558     D("Entering mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
559 
560     RenderWindowMessage msg = {};
561     msg.cmd = CMD_SETUP_SUBWINDOW;
562     msg.subwindow.parent = window;
563     msg.subwindow.wx = wx;
564     msg.subwindow.wy = wy;
565     msg.subwindow.ww = ww;
566     msg.subwindow.wh = wh;
567     msg.subwindow.fbw = fbw;
568     msg.subwindow.fbh = fbh;
569     msg.subwindow.dpr = dpr;
570     msg.subwindow.rotation = zRot;
571     msg.subwindow.deleteExisting = deleteExisting;
572     msg.subwindow.hideWindow = hideWindow;
573     mHasSubWindow = processMessage(msg);
574 
575     D("Exiting mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
576     return mHasSubWindow;
577 }
578 
removeSubWindow()579 bool RenderWindow::removeSubWindow() {
580     D("Entering mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
581     if (!mHasSubWindow) {
582         return false;
583     }
584     mHasSubWindow = false;
585     if (!useThread()) {
586         mRepostCommands.send(RepostCommand::Sync);
587         mRepostCommands.waitForEmpty();
588     }
589 
590     RenderWindowMessage msg = {};
591     msg.cmd = CMD_REMOVE_SUBWINDOW;
592     bool result = processMessage(msg);
593     D("Exiting result=%s\n", result ? "success" : "failure");
594     return result;
595 }
596 
setRotation(float zRot)597 void RenderWindow::setRotation(float zRot) {
598     D("Entering rotation=%f\n", zRot);
599     RenderWindowMessage msg = {};
600     msg.cmd = CMD_SET_ROTATION;
601     msg.rotation = zRot;
602     (void) processMessage(msg);
603     D("Exiting\n");
604 }
605 
setTranslation(float px,float py)606 void RenderWindow::setTranslation(float px, float py) {
607     D("Entering translation=%f,%f\n", px, py);
608     RenderWindowMessage msg = {};
609     msg.cmd = CMD_SET_TRANSLATION;
610     msg.trans.px = px;
611     msg.trans.py = py;
612     (void) processMessage(msg);
613     D("Exiting\n");
614 }
615 
setScreenMask(int width,int height,const unsigned char * rgbaData)616 void RenderWindow::setScreenMask(int width, int height, const unsigned char* rgbaData) {
617     if (FrameBuffer* fb = FrameBuffer::getFB()) {
618 #if GFXSTREAM_ENABLE_HOST_GLES
619         if (fb->hasEmulationGl()) {
620             fb->getTextureDraw()->setScreenMask(width, height, rgbaData);
621         }
622 #endif
623     }
624 }
625 
repaint()626 void RenderWindow::repaint() {
627     D("Entering\n");
628     RenderWindowMessage msg = {};
629     msg.cmd = CMD_REPAINT;
630     (void) processMessage(msg);
631     D("Exiting\n");
632 }
633 
hasGuestPostedAFrame()634 bool RenderWindow::hasGuestPostedAFrame() {
635     D("Entering\n");
636     RenderWindowMessage msg = {};
637     msg.cmd = CMD_HAS_GUEST_POSTED_A_FRAME;
638     bool res = processMessage(msg);
639     D("Exiting\n");
640     return res;
641 }
642 
resetGuestPostedAFrame()643 void RenderWindow::resetGuestPostedAFrame() {
644     D("Entering\n");
645     RenderWindowMessage msg = {};
646     msg.cmd = CMD_RESET_GUEST_POSTED_A_FRAME;
647     (void) processMessage(msg);
648     D("Exiting\n");
649 }
650 
setVsyncHz(int vsyncHz)651 void RenderWindow::setVsyncHz(int vsyncHz) {
652     D("Entering\n");
653     RenderWindowMessage msg = {};
654     msg.cmd = CMD_SET_VSYNC_HZ;
655     msg.vsyncHz = vsyncHz;
656     (void) processMessage(msg);
657     D("Exiting\n");
658 }
659 
setDisplayConfigs(int configId,int w,int h,int dpiX,int dpiY)660 void RenderWindow::setDisplayConfigs(int configId, int w, int h,
661                                      int dpiX, int dpiY) {
662     D("Entering\n");
663     RenderWindowMessage msg = {};
664     msg.cmd = CMD_SET_DISPLAY_CONFIGS;
665     msg.displayConfigs.configId = configId;
666     msg.displayConfigs.width = w;
667     msg.displayConfigs.height= h;
668     msg.displayConfigs.dpiX= dpiX;
669     msg.displayConfigs.dpiY = dpiY;
670     (void) processMessage(msg);
671     D("Exiting\n");
672 }
673 
setDisplayActiveConfig(int configId)674 void RenderWindow::setDisplayActiveConfig(int configId) {
675     D("Entering\n");
676     RenderWindowMessage msg = {};
677     msg.cmd = CMD_SET_DISPLAY_ACTIVE_CONFIG;
678     msg.displayActiveConfig = configId;
679     (void) processMessage(msg);
680     D("Exiting\n");
681 }
682 
processMessage(const RenderWindowMessage & msg)683 bool RenderWindow::processMessage(const RenderWindowMessage& msg) {
684     if (useThread()) {
685         if (msg.cmd == CMD_REPAINT) {
686             GL_LOG("Sending CMD_REPAINT to render window channel");
687         }
688         return mChannel->sendMessageAndGetResult(msg);
689     } else if (msg.cmd == CMD_REPAINT) {
690         GL_LOG("Sending CMD_REPAINT to reposting thread");
691         mRepostCommands.send(RepostCommand::Repost);
692         return true;
693     } else {
694         return msg.process();
695     }
696 }
697 
698 }  // namespace gfxstream
699