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