blob: f44254ee494ec19238635fecdf410b53c13d6d99 [file] [log] [blame]
Yahan Zhoud13d7c82023-05-15 15:56:55 -07001/*
2 * Copyright (C) 2023 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 "PostWorkerGl.h"
17
18#include "FrameBuffer.h"
19#include "gl/DisplayGl.h"
20#include "gl/DisplaySurfaceGl.h"
21#include "host-common/GfxstreamFatalError.h"
22#include "host-common/logging.h"
23#include "host-common/misc.h"
24
25namespace gfxstream {
26
27namespace {
28
29using emugl::ABORT_REASON_OTHER;
30using emugl::FatalError;
31using gl::DisplayGl;
32using gl::DisplaySurfaceGl;
33using gl::EmulationGl;
34using gl::s_egl;
35
36hwc_transform_t getTransformFromRotation(int rotation) {
37 switch (static_cast<int>(rotation / 90)) {
38 case 1:
39 return HWC_TRANSFORM_ROT_270;
40 case 2:
41 return HWC_TRANSFORM_ROT_180;
42 case 3:
43 return HWC_TRANSFORM_ROT_90;
44 default:
45 return HWC_TRANSFORM_NONE;
46 }
47}
48
49} // namespace
50
51PostWorkerGl::PostWorkerGl(bool mainThreadPostingOnly, FrameBuffer* fb, Compositor* compositor,
Yahan Zhou74525552023-06-20 15:20:42 -070052 DisplayGl* displayGl, gl::EmulationGl* emulationGl)
Yahan Zhoud13d7c82023-05-15 15:56:55 -070053 : PostWorker(mainThreadPostingOnly, fb, compositor),
54 m_displayGl(displayGl),
Yahan Zhou74525552023-06-20 15:20:42 -070055 mEmulationGl(emulationGl) {
Yahan Zhoud13d7c82023-05-15 15:56:55 -070056 if (!m_displayGl) {
57 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "PostWorker missing DisplayGl.";
58 }
59}
60
61void PostWorkerGl::screenshot(ColorBuffer* cb, int screenwidth, int screenheight, GLenum format,
62 GLenum type, int skinRotation, void* pixels, Rect rect) {
Joshua Duong3f93b752023-08-08 10:55:53 -070063 // See b/292237104.
64 mFb->lock();
Yahan Zhoud13d7c82023-05-15 15:56:55 -070065 cb->readToBytesScaled(screenwidth, screenheight, format, type, skinRotation, rect, pixels);
Joshua Duong3f93b752023-08-08 10:55:53 -070066 mFb->unlock();
Yahan Zhoud13d7c82023-05-15 15:56:55 -070067}
68
69std::shared_future<void> PostWorkerGl::postImpl(ColorBuffer* cb) {
Yahan Zhou26a9e442023-05-23 13:15:51 -070070 if (!mContextBound || m_mainThreadPostingOnly) {
Yahan Zhoud13d7c82023-05-15 15:56:55 -070071 // This might happen on headless mode
Yahan Zhou26a9e442023-05-23 13:15:51 -070072 // Also if posting on main thread, the context binding can get polluted easily, which
73 // requires frequent rebinds.
Yahan Zhoud13d7c82023-05-15 15:56:55 -070074 setupContext();
75 }
76 std::shared_future<void> completedFuture = std::async(std::launch::deferred, [] {}).share();
77 completedFuture.wait();
78
79 DisplayGl::Post post = {};
80
81 ComposeLayer postLayerOptions = {
82 .composeMode = HWC2_COMPOSITION_DEVICE,
83 .blendMode = HWC2_BLEND_MODE_NONE,
84 .alpha = 1.0f,
85 .transform = HWC_TRANSFORM_NONE,
86 };
87
88 const auto& multiDisplay = emugl::get_emugl_multi_display_operations();
Bo Hu0753b082023-10-24 08:54:07 -070089 const bool pixel_fold = multiDisplay.isPixelFold();
90 if (pixel_fold) {
Gurchetan Singh80345ad2024-04-19 14:22:03 -070091#ifdef CONFIG_AEMU
Bo Hu21366fd2024-02-29 11:29:44 -080092 if (emugl::shouldSkipDraw()) {
93 post.layers.clear();
94 } else {
95 post.layers.push_back(postWithOverlay(cb));
96 }
Gurchetan Singh80345ad2024-04-19 14:22:03 -070097#endif
Bo Hu0753b082023-10-24 08:54:07 -070098 }
99 else if (multiDisplay.isMultiDisplayEnabled()) {
Yahan Zhoud13d7c82023-05-15 15:56:55 -0700100 if (multiDisplay.isMultiDisplayWindow()) {
101 int32_t previousDisplayId = -1;
102 uint32_t currentDisplayId;
103 uint32_t currentDisplayColorBufferHandle;
104 while (multiDisplay.getNextMultiDisplay(previousDisplayId, &currentDisplayId,
105 /*x=*/nullptr,
106 /*y=*/nullptr,
107 /*w=*/nullptr,
108 /*h=*/nullptr,
109 /*dpi=*/nullptr,
110 /*flags=*/nullptr,
111 &currentDisplayColorBufferHandle)) {
112 previousDisplayId = currentDisplayId;
113
114 if (currentDisplayColorBufferHandle == 0) {
115 continue;
116 }
117 emugl::get_emugl_window_operations().paintMultiDisplayWindow(
118 currentDisplayId, currentDisplayColorBufferHandle);
119 }
120 post.layers.push_back(postWithOverlay(cb));
121 } else {
122 uint32_t combinedDisplayW = 0;
123 uint32_t combinedDisplayH = 0;
124 multiDisplay.getCombinedDisplaySize(&combinedDisplayW, &combinedDisplayH);
125
126 post.frameWidth = combinedDisplayW;
127 post.frameHeight = combinedDisplayH;
128
129 int32_t previousDisplayId = -1;
130 uint32_t currentDisplayId;
131 int32_t currentDisplayOffsetX;
132 int32_t currentDisplayOffsetY;
133 uint32_t currentDisplayW;
134 uint32_t currentDisplayH;
135 uint32_t currentDisplayColorBufferHandle;
136 while (multiDisplay.getNextMultiDisplay(
137 previousDisplayId, &currentDisplayId, &currentDisplayOffsetX,
138 &currentDisplayOffsetY, &currentDisplayW, &currentDisplayH,
139 /*dpi=*/nullptr,
140 /*flags=*/nullptr, &currentDisplayColorBufferHandle)) {
141 previousDisplayId = currentDisplayId;
142
143 if (currentDisplayW == 0 || currentDisplayH == 0 ||
144 (currentDisplayId != 0 && currentDisplayColorBufferHandle == 0)) {
145 continue;
146 }
147
148 ColorBuffer* currentCb =
149 currentDisplayId == 0
150 ? cb
151 : mFb->findColorBuffer(currentDisplayColorBufferHandle).get();
152 if (!currentCb) {
153 continue;
154 }
155
Bo Hu1d905082023-07-18 16:46:51 -0700156 const auto transform = getTransformFromRotation(mFb->getZrot());
157 postLayerOptions.transform = transform;
158 if ( transform == HWC_TRANSFORM_ROT_90 || transform == HWC_TRANSFORM_ROT_270) {
159 std::swap(currentDisplayW, currentDisplayH);
160 }
Yahan Zhoud13d7c82023-05-15 15:56:55 -0700161 postLayerOptions.displayFrame = {
162 .left = static_cast<int>(currentDisplayOffsetX),
163 .top = static_cast<int>(currentDisplayOffsetY),
164 .right = static_cast<int>(currentDisplayOffsetX + currentDisplayW),
165 .bottom = static_cast<int>(currentDisplayOffsetY + currentDisplayH),
166 };
167 postLayerOptions.crop = {
168 .left = 0.0f,
169 .top = static_cast<float>(currentCb->getHeight()),
170 .right = static_cast<float>(currentCb->getWidth()),
171 .bottom = 0.0f,
172 };
173
174 post.layers.push_back(DisplayGl::PostLayer{
175 .colorBuffer = currentCb,
176 .layerOptions = postLayerOptions,
177 });
178 }
179 }
180 } else if (emugl::get_emugl_window_operations().isFolded()) {
181 const float dpr = mFb->getDpr();
182
183 post.frameWidth = m_viewportWidth / dpr;
184 post.frameHeight = m_viewportHeight / dpr;
185
186 int displayOffsetX;
187 int displayOffsetY;
188 int displayW;
189 int displayH;
190 emugl::get_emugl_window_operations().getFoldedArea(&displayOffsetX, &displayOffsetY,
191 &displayW, &displayH);
192
193 postLayerOptions.displayFrame = {
194 .left = 0,
195 .top = 0,
196 .right = mFb->windowWidth(),
197 .bottom = mFb->windowHeight(),
198 };
199 postLayerOptions.crop = {
200 .left = static_cast<float>(displayOffsetX),
201 .top = static_cast<float>(displayOffsetY + displayH),
202 .right = static_cast<float>(displayOffsetX + displayW),
203 .bottom = static_cast<float>(displayOffsetY),
204 };
205 postLayerOptions.transform = getTransformFromRotation(mFb->getZrot());
206
207 post.layers.push_back(DisplayGl::PostLayer{
208 .colorBuffer = cb,
209 .layerOptions = postLayerOptions,
210 });
211 } else {
212 post.layers.push_back(postWithOverlay(cb));
213 }
214 return m_displayGl->post(post);
215}
216
217DisplayGl::PostLayer PostWorkerGl::postWithOverlay(ColorBuffer* cb) {
218 float dpr = mFb->getDpr();
219 int windowWidth = mFb->windowWidth();
220 int windowHeight = mFb->windowHeight();
221 float px = mFb->getPx();
222 float py = mFb->getPy();
223 int zRot = mFb->getZrot();
224 hwc_transform_t rotation = (hwc_transform_t)0;
225
226 // Find the x and y values at the origin when "fully scrolled."
227 // Multiply by 2 because the texture goes from -1 to 1, not 0 to 1.
228 // Multiply the windowing coordinates by DPR because they ignore
229 // DPR, but the viewport includes DPR.
230 float fx = 2.f * (m_viewportWidth - windowWidth * dpr) / (float)m_viewportWidth;
231 float fy = 2.f * (m_viewportHeight - windowHeight * dpr) / (float)m_viewportHeight;
232
233 // finally, compute translation values
234 float dx = px * fx;
235 float dy = py * fy;
236
237 return DisplayGl::PostLayer{
238 .colorBuffer = cb,
239 .overlayOptions =
240 DisplayGl::PostLayer::OverlayOptions{
241 .rotation = static_cast<float>(zRot),
242 .dx = dx,
243 .dy = dy,
244 },
245 };
246}
247
248// Called whenever the subwindow needs a refresh (FrameBuffer::setupSubWindow).
249// This rebinds the subwindow context (to account for
250// when the refresh is a display change, for instance)
251// and resets the posting viewport.
252void PostWorkerGl::viewportImpl(int width, int height) {
253 setupContext();
254 const float dpr = mFb->getDpr();
255 m_viewportWidth = width * dpr;
256 m_viewportHeight = height * dpr;
257
258 if (!m_displayGl) {
259 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "PostWorker missing DisplayGl.";
260 }
261 m_displayGl->viewport(m_viewportWidth, m_viewportHeight);
262}
263
264// Called when the subwindow refreshes, but there is no
265// last posted color buffer to show to the user. Instead of
266// displaying whatever happens to be in the back buffer,
267// clear() is useful for outputting consistent colors.
268void PostWorkerGl::clearImpl() {
Yahan Zhou26a9e442023-05-23 13:15:51 -0700269 if (!mContextBound || m_mainThreadPostingOnly) {
Yahan Zhoud13d7c82023-05-15 15:56:55 -0700270 // This might happen on headless mode
271 setupContext();
272 }
273 m_displayGl->clear();
274}
275
276std::shared_future<void> PostWorkerGl::composeImpl(const FlatComposeRequest& composeRequest) {
Yahan Zhou26a9e442023-05-23 13:15:51 -0700277 if (!mContextBound || m_mainThreadPostingOnly) {
Yahan Zhoud13d7c82023-05-15 15:56:55 -0700278 // This might happen on headless mode
279 setupContext();
280 }
281 return PostWorker::composeImpl(composeRequest);
282}
283
284void PostWorkerGl::setupContext() {
285 android::base::AutoLock lock(mMutex);
286 const auto* surface = getBoundSurface();
287 const DisplaySurfaceGl* surfaceGl = nullptr;
288 if (surface) {
289 surfaceGl = static_cast<const DisplaySurfaceGl*>(surface->getImpl());
290 } else {
Yahan Zhoud13d7c82023-05-15 15:56:55 -0700291 // Create a fake context.
Yahan Zhou74525552023-06-20 15:20:42 -0700292 // This could happen in AEMU with -qt-hide-window. Also due to an Intel bug
293 // this needs to happen on post thread.
294 // b/274313125
295 if (!mFakeWindowSurface) {
296 mFakeWindowSurface = mEmulationGl->createFakeWindowSurface();
297 }
Yahan Zhoud13d7c82023-05-15 15:56:55 -0700298 if (!mFakeWindowSurface) {
299 ERR("Post worker does not have a window surface.");
300 return;
301 }
302 surfaceGl = static_cast<const DisplaySurfaceGl*>(mFakeWindowSurface->getImpl());
303 }
304
305 // It will be no-op if it rebinds to the same context.
306 // We need to retry just in case the surface is changed.
307
308 // Also we could not use the scope context helper here,
309 // because (1) binds and unbinds happen in very different places;
310 // (2) they both need to happen in post thread, but the d'tor
311 // of PostWorker can happen in a different thread.
312 if (!surfaceGl->bindContext()) {
313 ERR("Failed to bind to post worker context.");
314 return;
315 }
316 mContextBound = true;
317}
318
319void PostWorkerGl::exitImpl() {
320 if (!mContextBound) {
321 return;
322 }
323 s_egl.eglMakeCurrent(s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY), nullptr, nullptr, nullptr);
324 mContextBound = false;
325}
326
Bo Hu1d905082023-07-18 16:46:51 -0700327} // namespace gfxstream