• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "PostWorker.h"
17 
18 #include <string.h>
19 
20 #include <chrono>
21 
22 #include "ColorBuffer.h"
23 #include "FrameBuffer.h"
24 #include "RenderThreadInfo.h"
25 #include "aemu/base/Tracing.h"
26 #include "host-common/logging.h"
27 #include "host-common/misc.h"
28 #include "vulkan/VkCommonOperations.h"
29 
sDefaultRunOnUiThread(UiUpdateFunc f,void * data,bool wait)30 static void sDefaultRunOnUiThread(UiUpdateFunc f, void* data, bool wait) {
31     (void)f;
32     (void)data;
33     (void)wait;
34 }
35 
36 namespace gfxstream {
37 
PostWorker(bool mainThreadPostingOnly,FrameBuffer * fb,Compositor * compositor)38 PostWorker::PostWorker(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor)
39     : mFb(fb),
40       m_compositor(compositor),
41       m_mainThreadPostingOnly(mainThreadPostingOnly),
42       m_runOnUiThread(m_mainThreadPostingOnly ? emugl::get_emugl_window_operations().runOnUiThread
43                                               : sDefaultRunOnUiThread) {}
44 
composeImpl(const FlatComposeRequest & composeRequest)45 std::shared_future<void> PostWorker::composeImpl(const FlatComposeRequest& composeRequest) {
46     std::shared_future<void> completedFuture =
47         std::async(std::launch::deferred, [] {}).share();
48     completedFuture.wait();
49 
50     if (!isComposeTargetReady(composeRequest.targetHandle)) {
51         ERR("The last composition on the target buffer hasn't completed.");
52     }
53 
54     Compositor::CompositionRequest compositorRequest = {};
55     compositorRequest.target = mFb->borrowColorBufferForComposition(composeRequest.targetHandle,
56                                                                     /*colorBufferIsTarget=*/true);
57     if (!compositorRequest.target) {
58         ERR("Compose target is null (cb=0x%x).", composeRequest.targetHandle);
59         return completedFuture;
60     }
61 
62     for (const ComposeLayer& guestLayer : composeRequest.layers) {
63         if (guestLayer.composeMode == HWC2_COMPOSITION_SOLID_COLOR) {
64             // HWC2_COMPOSITION_SOLID_COLOR has no colorbuffer backing.
65             auto& compositorLayer = compositorRequest.layers.emplace_back();
66             compositorLayer.props = guestLayer;
67         } else {
68             auto source = mFb->borrowColorBufferForComposition(guestLayer.cbHandle,
69                                                             /*colorBufferIsTarget=*/false);
70             if (!source) {
71                 continue;
72             }
73 
74             auto& compositorLayer = compositorRequest.layers.emplace_back();
75             compositorLayer.props = guestLayer;
76             compositorLayer.source = std::move(source);
77         }
78     }
79 
80     return m_compositor->compose(compositorRequest);
81 }
82 
block(std::promise<void> scheduledSignal,std::future<void> continueSignal)83 void PostWorker::block(std::promise<void> scheduledSignal, std::future<void> continueSignal) {
84     // Do not block mainthread.
85     if (m_mainThreadPostingOnly) {
86         return;
87     }
88     // MSVC STL doesn't support not copyable std::packaged_task. As a workaround, we use the
89     // copyable std::shared_ptr here.
90     auto block = std::make_shared<Post::Block>(Post::Block{
91         .scheduledSignal = std::move(scheduledSignal),
92         .continueSignal = std::move(continueSignal),
93     });
94     runTask(std::packaged_task<void()>([block] {
95         block->scheduledSignal.set_value();
96         block->continueSignal.wait();
97     }));
98 }
99 
~PostWorker()100 PostWorker::~PostWorker() {}
101 
post(ColorBuffer * cb,std::unique_ptr<Post::CompletionCallback> postCallback)102 void PostWorker::post(ColorBuffer* cb, std::unique_ptr<Post::CompletionCallback> postCallback) {
103     auto packagedPostCallback = std::shared_ptr<Post::CompletionCallback>(std::move(postCallback));
104     runTask(
105         std::packaged_task<void()>([cb, packagedPostCallback, this] {
106             auto completedFuture = postImpl(cb);
107             (*packagedPostCallback)(completedFuture);
108         }));
109 }
110 
exit()111 void PostWorker::exit() {
112     runTask(std::packaged_task<void()>([this] { exitImpl(); }));
113 }
114 
viewport(int width,int height)115 void PostWorker::viewport(int width, int height) {
116     runTask(std::packaged_task<void()>(
117         [width, height, this] { viewportImpl(width, height); }));
118 }
119 
compose(std::unique_ptr<FlatComposeRequest> composeRequest,std::unique_ptr<Post::CompletionCallback> composeCallback)120 void PostWorker::compose(std::unique_ptr<FlatComposeRequest> composeRequest,
121                          std::unique_ptr<Post::CompletionCallback> composeCallback) {
122     // std::shared_ptr(std::move(...)) is WA for MSFT STL implementation bug:
123     // https://developercommunity.visualstudio.com/t/unable-to-move-stdpackaged-task-into-any-stl-conta/108672
124     auto packagedComposeCallback =
125         std::shared_ptr<Post::CompletionCallback>(std::move(composeCallback));
126     auto packagedComposeRequest = std::shared_ptr<FlatComposeRequest>(std::move(composeRequest));
127     runTask(
128         std::packaged_task<void()>([packagedComposeCallback, packagedComposeRequest, this] {
129         auto completedFuture = composeImpl(*packagedComposeRequest);
130         m_composeTargetToComposeFuture.emplace(packagedComposeRequest->targetHandle,
131                                                completedFuture);
132         (*packagedComposeCallback)(completedFuture);
133         }));
134 }
135 
clear()136 void PostWorker::clear() {
137     runTask(std::packaged_task<void()>([this] { clearImpl(); }));
138 }
139 
runTask(std::packaged_task<void ()> task)140 void PostWorker::runTask(std::packaged_task<void()> task) {
141     using Task = std::packaged_task<void()>;
142     auto taskPtr = std::make_unique<Task>(std::move(task));
143     if (m_mainThreadPostingOnly) {
144         if (!m_runOnUiThread) {
145             ERR("m_runOnUiThread function ptr is NULL, going to crash");
146         }
147         m_runOnUiThread(
148             [](void* data) {
149                 std::unique_ptr<Task> taskPtr(reinterpret_cast<Task*>(data));
150                 (*taskPtr)();
151             },
152             taskPtr.release(), false);
153     } else {
154         (*taskPtr)();
155     }
156 }
157 
isComposeTargetReady(uint32_t targetHandle)158 bool PostWorker::isComposeTargetReady(uint32_t targetHandle) {
159     // Even if the target ColorBuffer has already been destroyed, the compose future should have
160     // been waited and set to the ready state.
161     for (auto i = m_composeTargetToComposeFuture.begin();
162          i != m_composeTargetToComposeFuture.end();) {
163         auto& composeFuture = i->second;
164         if (composeFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
165             i = m_composeTargetToComposeFuture.erase(i);
166         } else {
167             i++;
168         }
169     }
170     if (m_composeTargetToComposeFuture.find(targetHandle) == m_composeTargetToComposeFuture.end()) {
171         return true;
172     }
173     return false;
174 }
175 
176 }  // namespace gfxstream
177