• 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             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