1 /*
2  * Copyright (C) 2014 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 "DeferredLayerUpdater.h"
17 
18 #include "GlLayer.h"
19 #include "VkLayer.h"
20 #include "renderstate/RenderState.h"
21 #include "renderthread/EglManager.h"
22 #include "renderthread/RenderTask.h"
23 #include "utils/PaintUtils.h"
24 
25 namespace android {
26 namespace uirenderer {
27 
DeferredLayerUpdater(RenderState & renderState,CreateLayerFn createLayerFn,Layer::Api layerApi)28 DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
29                                            Layer::Api layerApi)
30         : mRenderState(renderState)
31         , mBlend(false)
32         , mSurfaceTexture(nullptr)
33         , mTransform(nullptr)
34         , mGLContextAttached(false)
35         , mUpdateTexImage(false)
36         , mLayer(nullptr)
37         , mLayerApi(layerApi)
38         , mCreateLayerFn(createLayerFn) {
39     renderState.registerDeferredLayerUpdater(this);
40 }
41 
~DeferredLayerUpdater()42 DeferredLayerUpdater::~DeferredLayerUpdater() {
43     setTransform(nullptr);
44     mRenderState.unregisterDeferredLayerUpdater(this);
45     destroyLayer();
46 }
47 
destroyLayer()48 void DeferredLayerUpdater::destroyLayer() {
49     if (!mLayer) {
50         return;
51     }
52 
53     if (mSurfaceTexture.get() && mLayerApi == Layer::Api::OpenGL && mGLContextAttached) {
54         status_t err = mSurfaceTexture->detachFromContext();
55         mGLContextAttached = false;
56         if (err != 0) {
57             // TODO: Elevate to fatal exception
58             ALOGE("Failed to detach SurfaceTexture from context %d", err);
59         }
60     }
61 
62     mLayer->postDecStrong();
63     mLayer = nullptr;
64 }
65 
setPaint(const SkPaint * paint)66 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
67     mAlpha = PaintUtils::getAlphaDirect(paint);
68     mMode = PaintUtils::getBlendModeDirect(paint);
69     if (paint) {
70         mColorFilter = paint->refColorFilter();
71     } else {
72         mColorFilter.reset();
73     }
74 }
75 
apply()76 void DeferredLayerUpdater::apply() {
77     if (!mLayer) {
78         mLayer = mCreateLayerFn(mRenderState, mWidth, mHeight, mColorFilter, mAlpha, mMode, mBlend);
79     }
80 
81     mLayer->setColorFilter(mColorFilter);
82     mLayer->setAlpha(mAlpha, mMode);
83 
84     if (mSurfaceTexture.get()) {
85         if (mLayer->getApi() == Layer::Api::Vulkan) {
86             if (mUpdateTexImage) {
87                 mUpdateTexImage = false;
88                 doUpdateVkTexImage();
89             }
90         } else {
91             LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
92                                 "apply surfaceTexture with non GL backend %x, GL %x, VK %x",
93                                 mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
94             if (!mGLContextAttached) {
95                 mGLContextAttached = true;
96                 mUpdateTexImage = true;
97                 mSurfaceTexture->attachToContext(static_cast<GlLayer*>(mLayer)->getTextureId());
98             }
99             if (mUpdateTexImage) {
100                 mUpdateTexImage = false;
101                 doUpdateTexImage();
102             }
103             GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
104             static_cast<GlLayer*>(mLayer)->setRenderTarget(renderTarget);
105         }
106         if (mTransform) {
107             mLayer->getTransform().load(*mTransform);
108             setTransform(nullptr);
109         }
110     }
111 }
112 
doUpdateTexImage()113 void DeferredLayerUpdater::doUpdateTexImage() {
114     LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
115                         "doUpdateTexImage non GL backend %x, GL %x, VK %x", mLayer->getApi(),
116                         Layer::Api::OpenGL, Layer::Api::Vulkan);
117     if (mSurfaceTexture->updateTexImage() == NO_ERROR) {
118         float transform[16];
119 
120         int64_t frameNumber = mSurfaceTexture->getFrameNumber();
121         // If the GLConsumer queue is in synchronous mode, need to discard all
122         // but latest frame, using the frame number to tell when we no longer
123         // have newer frames to target. Since we can't tell which mode it is in,
124         // do this unconditionally.
125         int dropCounter = 0;
126         while (mSurfaceTexture->updateTexImage() == NO_ERROR) {
127             int64_t newFrameNumber = mSurfaceTexture->getFrameNumber();
128             if (newFrameNumber == frameNumber) break;
129             frameNumber = newFrameNumber;
130             dropCounter++;
131         }
132 
133         bool forceFilter = false;
134         sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer();
135         if (buffer != nullptr) {
136             // force filtration if buffer size != layer size
137             forceFilter = mWidth != static_cast<int>(buffer->getWidth()) ||
138                           mHeight != static_cast<int>(buffer->getHeight());
139         }
140 
141 #if DEBUG_RENDERER
142         if (dropCounter > 0) {
143             RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
144         }
145 #endif
146         mSurfaceTexture->getTransformMatrix(transform);
147 
148         updateLayer(forceFilter, transform, mSurfaceTexture->getCurrentDataSpace());
149     }
150 }
151 
doUpdateVkTexImage()152 void DeferredLayerUpdater::doUpdateVkTexImage() {
153     LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::Vulkan,
154                         "updateLayer non Vulkan backend %x, GL %x, VK %x", mLayer->getApi(),
155                         Layer::Api::OpenGL, Layer::Api::Vulkan);
156 
157     static const mat4 identityMatrix;
158     updateLayer(false, identityMatrix.data, HAL_DATASPACE_UNKNOWN);
159 
160     VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
161     vkLayer->updateTexture();
162 }
163 
updateLayer(bool forceFilter,const float * textureTransform,android_dataspace dataspace)164 void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform,
165                                        android_dataspace dataspace) {
166     mLayer->setBlend(mBlend);
167     mLayer->setForceFilter(forceFilter);
168     mLayer->setSize(mWidth, mHeight);
169     mLayer->getTexTransform().load(textureTransform);
170     mLayer->setDataSpace(dataspace);
171 }
172 
detachSurfaceTexture()173 void DeferredLayerUpdater::detachSurfaceTexture() {
174     if (mSurfaceTexture.get()) {
175         destroyLayer();
176         mSurfaceTexture = nullptr;
177     }
178 }
179 
180 } /* namespace uirenderer */
181 } /* namespace android */
182