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 "ColorBuffer.h"
19 #include "DispatchTables.h"
20 #include "FrameBuffer.h"
21 #include "RenderThreadInfo.h"
22 #include "OpenGLESDispatch/EGLDispatch.h"
23 #include "OpenGLESDispatch/GLESv2Dispatch.h"
24 #include "host-common/misc.h"
25 #include <string.h>
26
27 #define POST_DEBUG 0
28 #if POST_DEBUG >= 1
29 #define DD(fmt, ...) \
30 fprintf(stderr, "%s:%d| " fmt, __func__, __LINE__, ##__VA_ARGS__)
31 #else
32 #define DD(fmt, ...) (void)0
33 #endif
34
sDefaultRunOnUiThread(UiUpdateFunc f,void * data,bool wait)35 static void sDefaultRunOnUiThread(UiUpdateFunc f, void* data, bool wait) {
36 (void)f;
37 (void)data;
38 (void)wait;
39 }
40
PostWorker(PostWorker::BindSubwinCallback && cb,bool mainThreadPostingOnly,EGLContext eglContext,EGLSurface)41 PostWorker::PostWorker(
42 PostWorker::BindSubwinCallback&& cb,
43 bool mainThreadPostingOnly,
44 EGLContext eglContext,
45 EGLSurface) :
46 mFb(FrameBuffer::getFB()),
47 mBindSubwin(cb),
48 m_mainThreadPostingOnly(mainThreadPostingOnly),
49 m_runOnUiThread(m_mainThreadPostingOnly ?
50 emugl::get_emugl_window_operations().runOnUiThread :
51 sDefaultRunOnUiThread),
52 mContext(eglContext) {}
53
fillMultiDisplayPostStruct(ComposeLayer * l,hwc_rect_t displayArea,hwc_frect_t cropArea,hwc_transform_t transform)54 void PostWorker::fillMultiDisplayPostStruct(ComposeLayer* l,
55 hwc_rect_t displayArea,
56 hwc_frect_t cropArea,
57 hwc_transform_t transform) {
58 l->composeMode = HWC2_COMPOSITION_DEVICE;
59 l->blendMode = HWC2_BLEND_MODE_NONE;
60 l->transform = transform;
61 l->alpha = 1.0;
62 l->displayFrame = displayArea;
63 l->crop = cropArea;
64 }
65
postImpl(ColorBuffer * cb)66 void PostWorker::postImpl(ColorBuffer* cb) {
67 // bind the subwindow eglSurface
68 if (!m_mainThreadPostingOnly && !m_initialized) {
69 m_initialized = mBindSubwin();
70 }
71 float dpr = mFb->getDpr();
72 int windowWidth = mFb->windowWidth();
73 int windowHeight = mFb->windowHeight();
74 float px = mFb->getPx();
75 float py = mFb->getPy();
76 int zRot = mFb->getZrot();
77 hwc_transform_t rotation = (hwc_transform_t)0;
78
79 cb->waitSync();
80
81 // Find the x and y values at the origin when "fully scrolled."
82 // Multiply by 2 because the texture goes from -1 to 1, not 0 to 1.
83 // Multiply the windowing coordinates by DPR because they ignore
84 // DPR, but the viewport includes DPR.
85 float fx = 2.f * (m_viewportWidth - windowWidth * dpr) / (float)m_viewportWidth;
86 float fy = 2.f * (m_viewportHeight - windowHeight * dpr) / (float)m_viewportHeight;
87
88 // finally, compute translation values
89 float dx = px * fx;
90 float dy = py * fy;
91
92 if (emugl::get_emugl_multi_display_operations().isMultiDisplayEnabled()) {
93 uint32_t combinedW, combinedH;
94 emugl::get_emugl_multi_display_operations().getCombinedDisplaySize(&combinedW, &combinedH);
95 mFb->getTextureDraw()->prepareForDrawLayer();
96 int32_t start_id = -1, x, y;
97 uint32_t id, w, h, c;
98 while(emugl::get_emugl_multi_display_operations().getNextMultiDisplay(start_id, &id,
99 &x, &y, &w, &h,
100 nullptr, nullptr,
101 &c)) {
102 if ((id != 0) && (w == 0 || h == 0 || c == 0)) {
103 start_id = id;
104 continue;
105 }
106 ColorBuffer* multiDisplayCb = id == 0 ? cb : mFb->findColorBuffer(c).get();
107 if (multiDisplayCb == nullptr) {
108 start_id = id;
109 continue;
110 }
111 ComposeLayer l;
112 hwc_rect_t displayArea = { .left = (int)x,
113 .top = (int)y,
114 .right = (int)(x + w),
115 .bottom = (int)(y + h) };
116 hwc_frect_t cropArea = { .left = 0.0,
117 .top = (float)multiDisplayCb->getHeight(),
118 .right = (float)multiDisplayCb->getWidth(),
119 .bottom = 0.0 };
120 fillMultiDisplayPostStruct(&l, displayArea, cropArea, rotation);
121 multiDisplayCb->postLayer(&l, combinedW, combinedH);
122 start_id = id;
123 }
124 mFb->getTextureDraw()->cleanupForDrawLayer();
125 }
126 else if (emugl::get_emugl_window_operations().isFolded()) {
127 mFb->getTextureDraw()->prepareForDrawLayer();
128 ComposeLayer l;
129 int x, y, w, h;
130 emugl::get_emugl_window_operations().getFoldedArea(&x, &y, &w, &h);
131 hwc_rect_t displayArea = { .left = 0,
132 .top = 0,
133 .right = windowWidth,
134 .bottom = windowHeight };
135 hwc_frect_t cropArea = { .left = (float)x,
136 .top = (float)(y + h),
137 .right = (float)(x + w),
138 .bottom = (float)y };
139 switch ((int)zRot/90) {
140 case 1:
141 rotation = HWC_TRANSFORM_ROT_270;
142 break;
143 case 2:
144 rotation = HWC_TRANSFORM_ROT_180;
145 break;
146 case 3:
147 rotation = HWC_TRANSFORM_ROT_90;
148 break;
149 default: ;
150 }
151
152 fillMultiDisplayPostStruct(&l, displayArea, cropArea, rotation);
153 cb->postLayer(&l, m_viewportWidth/dpr, m_viewportHeight/dpr);
154 mFb->getTextureDraw()->cleanupForDrawLayer();
155 }
156 else {
157 // render the color buffer to the window and apply the overlay
158 GLuint tex = cb->scale();
159 cb->postWithOverlay(tex, zRot, dx, dy);
160 }
161
162 s_egl.eglSwapBuffers(mFb->getDisplay(), mFb->getWindowSurface());
163 }
164
165 // Called whenever the subwindow needs a refresh (FrameBuffer::setupSubWindow).
166 // This rebinds the subwindow context (to account for
167 // when the refresh is a display change, for instance)
168 // and resets the posting viewport.
viewportImpl(int width,int height)169 void PostWorker::viewportImpl(int width, int height) {
170 // rebind the subwindow eglSurface unconditionally---
171 // this could be from a display change
172 if (!m_mainThreadPostingOnly) {
173 m_initialized = mBindSubwin();
174 }
175
176 float dpr = mFb->getDpr();
177 m_viewportWidth = width * dpr;
178 m_viewportHeight = height * dpr;
179 s_gles2.glViewport(0, 0, m_viewportWidth, m_viewportHeight);
180 }
181
182 // Called when the subwindow refreshes, but there is no
183 // last posted color buffer to show to the user. Instead of
184 // displaying whatever happens to be in the back buffer,
185 // clear() is useful for outputting consistent colors.
clearImpl()186 void PostWorker::clearImpl() {
187 #ifndef __linux__
188 s_gles2.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
189 GL_STENCIL_BUFFER_BIT);
190 s_egl.eglSwapBuffers(mFb->getDisplay(), mFb->getWindowSurface());
191 #endif
192 }
193
composeImpl(ComposeDevice * p)194 void PostWorker::composeImpl(ComposeDevice* p) {
195 // bind the subwindow eglSurface
196 if (!m_mainThreadPostingOnly && !m_initialized) {
197 m_initialized = mBindSubwin();
198 }
199 ComposeLayer* l = (ComposeLayer*)p->layer;
200 GLint vport[4] = { 0, };
201 s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
202 s_gles2.glViewport(0, 0, mFb->getWidth(),mFb->getHeight());
203 if (!m_composeFbo) {
204 s_gles2.glGenFramebuffers(1, &m_composeFbo);
205 }
206 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, m_composeFbo);
207
208 auto cbPtr = mFb->findColorBuffer(p->targetHandle);
209
210 if (!cbPtr) {
211 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
212 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
213 return;
214 }
215
216 s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER,
217 GL_COLOR_ATTACHMENT0_OES,
218 GL_TEXTURE_2D,
219 cbPtr->getTexture(),
220 0);
221
222 DD("worker compose %d layers\n", p->numLayers);
223 mFb->getTextureDraw()->prepareForDrawLayer();
224 for (int i = 0; i < p->numLayers; i++, l++) {
225 DD("\tcomposeMode %d color %d %d %d %d blendMode "
226 "%d alpha %f transform %d %d %d %d %d "
227 "%f %f %f %f\n",
228 l->composeMode, l->color.r, l->color.g, l->color.b,
229 l->color.a, l->blendMode, l->alpha, l->transform,
230 l->displayFrame.left, l->displayFrame.top,
231 l->displayFrame.right, l->displayFrame.bottom,
232 l->crop.left, l->crop.top, l->crop.right,
233 l->crop.bottom);
234 composeLayer(l, mFb->getWidth(), mFb->getHeight());
235 }
236
237 cbPtr->setSync();
238
239 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
240 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
241 mFb->getTextureDraw()->cleanupForDrawLayer();
242 }
243
composev2Impl(ComposeDevice_v2 * p)244 void PostWorker::composev2Impl(ComposeDevice_v2* p) {
245 // bind the subwindow eglSurface
246 if (!m_mainThreadPostingOnly && !m_initialized) {
247 m_initialized = mBindSubwin();
248 }
249 ComposeLayer* l = (ComposeLayer*)p->layer;
250 GLint vport[4] = { 0, };
251 s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
252 uint32_t w, h;
253 emugl::get_emugl_multi_display_operations().getMultiDisplay(p->displayId,
254 nullptr,
255 nullptr,
256 &w,
257 &h,
258 nullptr,
259 nullptr,
260 nullptr);
261 s_gles2.glViewport(0, 0, w, h);
262 if (!m_composeFbo) {
263 s_gles2.glGenFramebuffers(1, &m_composeFbo);
264 }
265 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, m_composeFbo);
266
267 auto cbPtr = mFb->findColorBuffer(p->targetHandle);
268
269 if (!cbPtr) {
270 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
271 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
272 return;
273 }
274
275 s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER,
276 GL_COLOR_ATTACHMENT0_OES,
277 GL_TEXTURE_2D,
278 cbPtr->getTexture(),
279 0);
280
281 DD("worker compose %d layers\n", p->numLayers);
282 mFb->getTextureDraw()->prepareForDrawLayer();
283 for (int i = 0; i < p->numLayers; i++, l++) {
284 DD("\tcomposeMode %d color %d %d %d %d blendMode "
285 "%d alpha %f transform %d %d %d %d %d "
286 "%f %f %f %f\n",
287 l->composeMode, l->color.r, l->color.g, l->color.b,
288 l->color.a, l->blendMode, l->alpha, l->transform,
289 l->displayFrame.left, l->displayFrame.top,
290 l->displayFrame.right, l->displayFrame.bottom,
291 l->crop.left, l->crop.top, l->crop.right,
292 l->crop.bottom);
293 composeLayer(l, w, h);
294 }
295
296 cbPtr->setSync();
297 s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
298 s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
299 mFb->getTextureDraw()->cleanupForDrawLayer();
300 }
301
bind()302 void PostWorker::bind() {
303 if (m_mainThreadPostingOnly) {
304 if (mFb->getDisplay() != EGL_NO_DISPLAY) {
305 EGLint res = s_egl.eglMakeCurrent(mFb->getDisplay(), mFb->getWindowSurface(), mFb->getWindowSurface(), mContext);
306 if (!res) fprintf(stderr, "%s: error in binding: 0x%x\n", __func__, s_egl.eglGetError());
307 } else {
308 fprintf(stderr, "%s: no display!\n", __func__);
309 }
310 } else {
311 mBindSubwin();
312 }
313 }
314
unbind()315 void PostWorker::unbind() {
316 if (mFb->getDisplay() != EGL_NO_DISPLAY) {
317 s_egl.eglMakeCurrent(mFb->getDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE,
318 EGL_NO_CONTEXT);
319 }
320 }
321
composeLayer(ComposeLayer * l,uint32_t w,uint32_t h)322 void PostWorker::composeLayer(ComposeLayer* l, uint32_t w, uint32_t h) {
323 if (l->composeMode == HWC2_COMPOSITION_DEVICE) {
324 ColorBufferPtr cb = mFb->findColorBuffer(l->cbHandle);
325 if (!cb) {
326 // bad colorbuffer handle
327 // ERR("%s: fail to find colorbuffer %d\n", __FUNCTION__, l->cbHandle);
328 return;
329 }
330 cb->postLayer(l, w, h);
331 }
332 else {
333 // no Colorbuffer associated with SOLID_COLOR mode
334 mFb->getTextureDraw()->drawLayer(l, w, h, 1, 1, 0);
335 }
336 }
337
screenshot(ColorBuffer * cb,int width,int height,GLenum format,GLenum type,int rotation,void * pixels)338 void PostWorker::screenshot(
339 ColorBuffer* cb,
340 int width,
341 int height,
342 GLenum format,
343 GLenum type,
344 int rotation,
345 void* pixels) {
346 cb->readPixelsScaled(
347 width, height, format, type, rotation, pixels);
348 }
349
~PostWorker()350 PostWorker::~PostWorker() {
351 if (mFb->getDisplay() != EGL_NO_DISPLAY) {
352 s_egl.eglMakeCurrent(mFb->getDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE,
353 EGL_NO_CONTEXT);
354 }
355 }
356
post(ColorBuffer * cb)357 void PostWorker::post(ColorBuffer* cb) {
358 if (m_mainThreadPostingOnly) {
359 PostArgs args = {
360 .postCb = cb,
361 };
362
363 m_toUiThread.send(args);
364
365 m_runOnUiThread([](void* data) {
366 PostWorker* p = (PostWorker*)data;
367 PostArgs uiThreadArgs;
368 p->m_toUiThread.receive(&uiThreadArgs);
369 p->bind();
370 p->postImpl(uiThreadArgs.postCb);
371 },
372 this,
373 false /* no wait */);
374 } else {
375 postImpl(cb);
376 }
377 }
378
viewport(int width,int height)379 void PostWorker::viewport(int width, int height) {
380 if (m_mainThreadPostingOnly) {
381 PostArgs args = {
382 .width = width,
383 .height = height,
384 };
385
386 m_toUiThread.send(args);
387
388 m_runOnUiThread([](void* data) {
389 PostWorker* p = (PostWorker*)data;
390 PostArgs uiThreadArgs;
391 p->m_toUiThread.receive(&uiThreadArgs);
392 p->bind();
393 p->viewportImpl(uiThreadArgs.width, uiThreadArgs.height);
394 },
395 this,
396 false /* no wait */);
397 } else {
398 viewportImpl(width, height);
399 }
400 }
401
compose(ComposeDevice * p,uint32_t bufferSize)402 void PostWorker::compose(ComposeDevice* p, uint32_t bufferSize) {
403 if (m_mainThreadPostingOnly) {
404 PostArgs args;
405 std::vector<char> buffer(bufferSize, 0);
406 memcpy(buffer.data(), p, bufferSize);
407 args.composeBuffer = buffer;
408
409 m_toUiThread.send(args);
410
411 m_runOnUiThread([](void* data) {
412 PostWorker* p = (PostWorker*)data;
413 PostArgs uiThreadArgs;
414 p->m_toUiThread.receive(&uiThreadArgs);
415 p->bind();
416 p->composeImpl((ComposeDevice*)uiThreadArgs.composeBuffer.data());
417 },
418 this,
419 false /* no wait */);
420 } else {
421 composeImpl(p);
422 }
423 }
424
compose(ComposeDevice_v2 * p,uint32_t bufferSize)425 void PostWorker::compose(ComposeDevice_v2* p, uint32_t bufferSize) {
426 if (m_mainThreadPostingOnly) {
427 PostArgs args;
428 std::vector<char> buffer(bufferSize, 0);
429 memcpy(buffer.data(), p, bufferSize);
430 args.composeBuffer = buffer;
431
432 m_toUiThread.send(args);
433
434 m_runOnUiThread([](void* data) {
435 PostWorker* p = (PostWorker*)data;
436 PostArgs uiThreadArgs;
437 p->m_toUiThread.receive(&uiThreadArgs);
438 p->bind();
439 p->composev2Impl((ComposeDevice_v2*)uiThreadArgs.composeBuffer.data());
440 },
441 this,
442 false /* no wait */);
443 } else {
444 composev2Impl(p);
445 }
446 }
447
clear()448 void PostWorker::clear() {
449 if (m_mainThreadPostingOnly) {
450 PostArgs args = {
451 .postCb = 0,
452 };
453
454 m_toUiThread.send(args);
455
456 m_runOnUiThread([](void* data) {
457 PostWorker* p = (PostWorker*)data;
458 PostArgs uiThreadArgs;
459 p->m_toUiThread.receive(&uiThreadArgs);
460 p->bind();
461 p->clearImpl();
462 },
463 this,
464 false /* no wait */);
465 } else {
466 clearImpl();
467 }
468 }
469
470