• 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 "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