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/GfxstreamFatalError.h"
27 #include "host-common/logging.h"
28 #include "host-common/misc.h"
29 #include "vulkan/VkCommonOperations.h"
30
sDefaultRunOnUiThread(UiUpdateFunc f,void * data,bool wait)31 static void sDefaultRunOnUiThread(UiUpdateFunc f, void* data, bool wait) {
32 (void)f;
33 (void)data;
34 (void)wait;
35 }
36
37 namespace gfxstream {
38 namespace {
39
40 using emugl::ABORT_REASON_OTHER;
41 using emugl::FatalError;
42
getTransformFromRotation(int rotation)43 hwc_transform_t getTransformFromRotation(int rotation) {
44 switch (static_cast<int>(rotation / 90)) {
45 case 1:
46 return HWC_TRANSFORM_ROT_270;
47 case 2:
48 return HWC_TRANSFORM_ROT_180;
49 case 3:
50 return HWC_TRANSFORM_ROT_90;
51 default:
52 return HWC_TRANSFORM_NONE;
53 }
54 }
55
56 } // namespace
57
PostWorker(bool mainThreadPostingOnly,FrameBuffer * fb,Compositor * compositor)58 PostWorker::PostWorker(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor)
59 : mFb(fb),
60 m_mainThreadPostingOnly(mainThreadPostingOnly),
61 m_runOnUiThread(m_mainThreadPostingOnly ? emugl::get_emugl_window_operations().runOnUiThread
62 : sDefaultRunOnUiThread),
63 m_compositor(compositor) {}
64
composeImpl(const FlatComposeRequest & composeRequest)65 std::shared_future<void> PostWorker::composeImpl(const FlatComposeRequest& composeRequest) {
66 std::shared_future<void> completedFuture =
67 std::async(std::launch::deferred, [] {}).share();
68 completedFuture.wait();
69
70 if (!isComposeTargetReady(composeRequest.targetHandle)) {
71 ERR("The last composition on the target buffer hasn't completed.");
72 }
73
74 Compositor::CompositionRequest compositorRequest = {};
75 compositorRequest.target = mFb->borrowColorBufferForComposition(composeRequest.targetHandle,
76 /*colorBufferIsTarget=*/true);
77 if (!compositorRequest.target) {
78 ERR("Compose target is null (cb=0x%x).", composeRequest.targetHandle);
79 return completedFuture;
80 }
81
82 for (const ComposeLayer& guestLayer : composeRequest.layers) {
83 if (guestLayer.composeMode == HWC2_COMPOSITION_SOLID_COLOR) {
84 // HWC2_COMPOSITION_SOLID_COLOR has no colorbuffer backing.
85 auto& compositorLayer = compositorRequest.layers.emplace_back();
86 compositorLayer.props = guestLayer;
87 } else {
88 auto source = mFb->borrowColorBufferForComposition(guestLayer.cbHandle,
89 /*colorBufferIsTarget=*/false);
90 if (!source) {
91 continue;
92 }
93
94 auto& compositorLayer = compositorRequest.layers.emplace_back();
95 compositorLayer.props = guestLayer;
96 compositorLayer.source = std::move(source);
97 }
98 }
99
100 return m_compositor->compose(compositorRequest);
101 }
102
block(std::promise<void> scheduledSignal,std::future<void> continueSignal)103 void PostWorker::block(std::promise<void> scheduledSignal, std::future<void> continueSignal) {
104 // Do not block mainthread.
105 if (m_mainThreadPostingOnly) {
106 return;
107 }
108 // MSVC STL doesn't support not copyable std::packaged_task. As a workaround, we use the
109 // copyable std::shared_ptr here.
110 auto block = std::make_shared<Post::Block>(Post::Block{
111 .scheduledSignal = std::move(scheduledSignal),
112 .continueSignal = std::move(continueSignal),
113 });
114 runTask(std::packaged_task<void()>([block] {
115 block->scheduledSignal.set_value();
116 block->continueSignal.wait();
117 }));
118 }
119
~PostWorker()120 PostWorker::~PostWorker() {}
121
post(ColorBuffer * cb,std::unique_ptr<Post::CompletionCallback> postCallback)122 void PostWorker::post(ColorBuffer* cb, std::unique_ptr<Post::CompletionCallback> postCallback) {
123 auto packagedPostCallback = std::shared_ptr<Post::CompletionCallback>(std::move(postCallback));
124 runTask(
125 std::packaged_task<void()>([cb, packagedPostCallback, this] {
126 auto completedFuture = postImpl(cb);
127 (*packagedPostCallback)(completedFuture);
128 }));
129 }
130
exit()131 void PostWorker::exit() {
132 runTask(std::packaged_task<void()>([this] { exitImpl(); }));
133 }
134
viewport(int width,int height)135 void PostWorker::viewport(int width, int height) {
136 runTask(std::packaged_task<void()>(
137 [width, height, this] { viewportImpl(width, height); }));
138 }
139
compose(std::unique_ptr<FlatComposeRequest> composeRequest,std::unique_ptr<Post::CompletionCallback> composeCallback)140 void PostWorker::compose(std::unique_ptr<FlatComposeRequest> composeRequest,
141 std::unique_ptr<Post::CompletionCallback> composeCallback) {
142 // std::shared_ptr(std::move(...)) is WA for MSFT STL implementation bug:
143 // https://developercommunity.visualstudio.com/t/unable-to-move-stdpackaged-task-into-any-stl-conta/108672
144 auto packagedComposeCallback =
145 std::shared_ptr<Post::CompletionCallback>(std::move(composeCallback));
146 auto packagedComposeRequest = std::shared_ptr<FlatComposeRequest>(std::move(composeRequest));
147 runTask(
148 std::packaged_task<void()>([packagedComposeCallback, packagedComposeRequest, this] {
149 auto completedFuture = composeImpl(*packagedComposeRequest);
150 m_composeTargetToComposeFuture.emplace(packagedComposeRequest->targetHandle,
151 completedFuture);
152 (*packagedComposeCallback)(completedFuture);
153 }));
154 }
155
clear()156 void PostWorker::clear() {
157 runTask(std::packaged_task<void()>([this] { clearImpl(); }));
158 }
159
runTask(std::packaged_task<void ()> task)160 void PostWorker::runTask(std::packaged_task<void()> task) {
161 using Task = std::packaged_task<void()>;
162 auto taskPtr = std::make_unique<Task>(std::move(task));
163 if (m_mainThreadPostingOnly) {
164 m_runOnUiThread(
165 [](void* data) {
166 std::unique_ptr<Task> taskPtr(reinterpret_cast<Task*>(data));
167 (*taskPtr)();
168 },
169 taskPtr.release(), false);
170 } else {
171 (*taskPtr)();
172 }
173 }
174
isComposeTargetReady(uint32_t targetHandle)175 bool PostWorker::isComposeTargetReady(uint32_t targetHandle) {
176 // Even if the target ColorBuffer has already been destroyed, the compose future should have
177 // been waited and set to the ready state.
178 for (auto i = m_composeTargetToComposeFuture.begin();
179 i != m_composeTargetToComposeFuture.end();) {
180 auto& composeFuture = i->second;
181 if (composeFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
182 i = m_composeTargetToComposeFuture.erase(i);
183 } else {
184 i++;
185 }
186 }
187 if (m_composeTargetToComposeFuture.find(targetHandle) == m_composeTargetToComposeFuture.end()) {
188 return true;
189 }
190 return false;
191 }
192
193 } // namespace gfxstream
194