1 /*
2  * Copyright 2019 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 
17 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 
19 #include <android-base/stringprintf.h>
20 #include <android/native_window.h>
21 #include <compositionengine/CompositionEngine.h>
22 #include <compositionengine/Display.h>
23 #include <compositionengine/DisplaySurface.h>
24 #include <compositionengine/RenderSurfaceCreationArgs.h>
25 #include <compositionengine/impl/DumpHelpers.h>
26 #include <compositionengine/impl/OutputCompositionState.h>
27 #include <compositionengine/impl/RenderSurface.h>
28 #include <log/log.h>
29 #include <renderengine/ExternalTexture.h>
30 #include <renderengine/RenderEngine.h>
31 #include <renderengine/impl/ExternalTexture.h>
32 #include <system/window.h>
33 #include <ui/GraphicBuffer.h>
34 #include <ui/Rect.h>
35 #include <utils/Trace.h>
36 
37 // TODO(b/129481165): remove the #pragma below and fix conversion issues
38 #pragma clang diagnostic push
39 #pragma clang diagnostic ignored "-Wconversion"
40 
41 #include "DisplayHardware/HWComposer.h"
42 
43 // TODO(b/129481165): remove the #pragma below and fix conversion issues
44 #pragma clang diagnostic pop // ignored "-Wconversion"
45 
46 namespace android::compositionengine {
47 
48 RenderSurface::~RenderSurface() = default;
49 
50 namespace impl {
51 
52 constexpr auto DEFAULT_USAGE = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
53 
createRenderSurface(const compositionengine::CompositionEngine & compositionEngine,compositionengine::Display & display,const compositionengine::RenderSurfaceCreationArgs & args)54 std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
55         const compositionengine::CompositionEngine& compositionEngine,
56         compositionengine::Display& display,
57         const compositionengine::RenderSurfaceCreationArgs& args) {
58     return std::make_unique<RenderSurface>(compositionEngine, display, args);
59 }
60 
RenderSurface(const CompositionEngine & compositionEngine,Display & display,const RenderSurfaceCreationArgs & args)61 RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display& display,
62                              const RenderSurfaceCreationArgs& args)
63       : mCompositionEngine(compositionEngine),
64         mDisplay(display),
65         mNativeWindow(args.nativeWindow),
66         mDisplaySurface(args.displaySurface),
67         mSize(args.displayWidth, args.displayHeight),
68         mMaxTextureCacheSize(args.maxTextureCacheSize) {
69     LOG_ALWAYS_FATAL_IF(!mNativeWindow);
70 }
71 
~RenderSurface()72 RenderSurface::~RenderSurface() {
73     ANativeWindow* const window = mNativeWindow.get();
74     native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
75 }
76 
isValid() const77 bool RenderSurface::isValid() const {
78     return mSize.isValid();
79 }
80 
initialize()81 void RenderSurface::initialize() {
82     ANativeWindow* const window = mNativeWindow.get();
83 
84     int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
85     ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
86     status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
87     ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
88     status = native_window_set_usage(window, DEFAULT_USAGE);
89     ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
90 }
91 
getSize() const92 const ui::Size& RenderSurface::getSize() const {
93     return mSize;
94 }
95 
getClientTargetAcquireFence() const96 const sp<Fence>& RenderSurface::getClientTargetAcquireFence() const {
97     return mDisplaySurface->getClientTargetAcquireFence();
98 }
99 
setDisplaySize(const ui::Size & size)100 void RenderSurface::setDisplaySize(const ui::Size& size) {
101     mDisplaySurface->resizeBuffers(size);
102     mSize = size;
103 }
104 
setBufferDataspace(ui::Dataspace dataspace)105 void RenderSurface::setBufferDataspace(ui::Dataspace dataspace) {
106     native_window_set_buffers_data_space(mNativeWindow.get(),
107                                          static_cast<android_dataspace>(dataspace));
108 }
109 
setBufferPixelFormat(ui::PixelFormat pixelFormat)110 void RenderSurface::setBufferPixelFormat(ui::PixelFormat pixelFormat) {
111     native_window_set_buffers_format(mNativeWindow.get(), static_cast<int32_t>(pixelFormat));
112 }
113 
setProtected(bool useProtected)114 void RenderSurface::setProtected(bool useProtected) {
115     uint64_t usageFlags = DEFAULT_USAGE;
116     if (useProtected) {
117         usageFlags |= GRALLOC_USAGE_PROTECTED;
118     }
119     const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
120     ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
121     if (status == NO_ERROR) {
122         mProtected = useProtected;
123     }
124 }
125 
beginFrame(bool mustRecompose)126 status_t RenderSurface::beginFrame(bool mustRecompose) {
127     return mDisplaySurface->beginFrame(mustRecompose);
128 }
129 
prepareFrame(bool usesClientComposition,bool usesDeviceComposition)130 void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComposition) {
131     const auto compositionType = [=] {
132         using CompositionType = DisplaySurface::CompositionType;
133 
134         if (usesClientComposition && usesDeviceComposition) return CompositionType::Mixed;
135         if (usesClientComposition) return CompositionType::Gpu;
136         if (usesDeviceComposition) return CompositionType::Hwc;
137 
138         // Nothing to do -- when turning the screen off we get a frame like
139         // this. Call it a HWC frame since we won't be doing any GPU work but
140         // will do a prepare/set cycle.
141         return CompositionType::Hwc;
142     }();
143 
144     if (status_t result = mDisplaySurface->prepareFrame(compositionType); result != NO_ERROR) {
145         ALOGE("updateCompositionType failed for %s: %d (%s)", mDisplay.getName().c_str(), result,
146               strerror(-result));
147     }
148 }
149 
dequeueBuffer(base::unique_fd * bufferFence)150 std::shared_ptr<renderengine::ExternalTexture> RenderSurface::dequeueBuffer(
151         base::unique_fd* bufferFence) {
152     ATRACE_CALL();
153     int fd = -1;
154     ANativeWindowBuffer* buffer = nullptr;
155 
156     status_t result = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
157 
158     if (result != NO_ERROR) {
159         ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
160               mDisplay.getName().c_str(), result);
161         // Return fast here as we can't do much more - any rendering we do
162         // now will just be wrong.
163         return mTexture;
164     }
165 
166     ALOGW_IF(mTexture != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
167              mTexture->getBuffer()->getNativeBuffer()->handle);
168 
169     sp<GraphicBuffer> newBuffer = GraphicBuffer::from(buffer);
170 
171     std::shared_ptr<renderengine::ExternalTexture> texture;
172 
173     for (auto it = mTextureCache.begin(); it != mTextureCache.end(); it++) {
174         const auto& cachedTexture = *it;
175         if (cachedTexture->getBuffer()->getId() == newBuffer->getId()) {
176             texture = cachedTexture;
177             mTextureCache.erase(it);
178             break;
179         }
180     }
181 
182     if (texture) {
183         mTexture = texture;
184     } else {
185         mTexture = std::make_shared<
186                 renderengine::impl::ExternalTexture>(GraphicBuffer::from(buffer),
187                                                      mCompositionEngine.getRenderEngine(),
188                                                      renderengine::impl::ExternalTexture::Usage::
189                                                              WRITEABLE);
190     }
191     mTextureCache.push_back(mTexture);
192     if (mTextureCache.size() > mMaxTextureCacheSize) {
193         mTextureCache.erase(mTextureCache.begin());
194     }
195 
196     *bufferFence = base::unique_fd(fd);
197 
198     return mTexture;
199 }
200 
queueBuffer(base::unique_fd readyFence,float hdrSdrRatio)201 void RenderSurface::queueBuffer(base::unique_fd readyFence, float hdrSdrRatio) {
202     auto& state = mDisplay.getState();
203 
204     if (state.usesClientComposition || state.flipClientTarget) {
205         // hasFlipClientTargetRequest could return true even if we haven't
206         // dequeued a buffer before. Try dequeueing one if we don't have a
207         // buffer ready.
208         if (mTexture == nullptr) {
209             ALOGI("Attempting to queue a client composited buffer without one "
210                   "previously dequeued for display [%s]. Attempting to dequeue "
211                   "a scratch buffer now",
212                   mDisplay.getName().c_str());
213             // We shouldn't deadlock here, since mTexture == nullptr only
214             // after a successful call to queueBuffer, or if dequeueBuffer has
215             // never been called.
216             base::unique_fd unused;
217             dequeueBuffer(&unused);
218         }
219 
220         if (mTexture == nullptr) {
221             ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str());
222         } else {
223             status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
224                                                          mTexture->getBuffer()->getNativeBuffer(),
225                                                          dup(readyFence));
226             if (result != NO_ERROR) {
227                 ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
228                       result);
229                 // We risk blocking on dequeueBuffer if the primary display failed
230                 // to queue up its buffer, so crash here.
231                 if (!mDisplay.isVirtual()) {
232                     LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
233                 } else {
234                     mNativeWindow->cancelBuffer(mNativeWindow.get(),
235                                                 mTexture->getBuffer()->getNativeBuffer(),
236                                                 dup(readyFence));
237                 }
238             }
239 
240             mTexture = nullptr;
241         }
242     }
243 
244     status_t result = mDisplaySurface->advanceFrame(hdrSdrRatio);
245     if (result != NO_ERROR) {
246         ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplay.getName().c_str(), result);
247     }
248 }
249 
onPresentDisplayCompleted()250 void RenderSurface::onPresentDisplayCompleted() {
251     mDisplaySurface->onFrameCommitted();
252 }
253 
dump(std::string & out) const254 void RenderSurface::dump(std::string& out) const {
255     using android::base::StringAppendF;
256 
257     out.append("   Composition RenderSurface State:");
258 
259     out.append("\n   ");
260 
261     dumpVal(out, "size", mSize);
262     StringAppendF(&out, "ANativeWindow=%p (format %d) ", mNativeWindow.get(),
263                   ANativeWindow_getFormat(mNativeWindow.get()));
264     out.append("\n");
265 
266     String8 surfaceDump;
267     mDisplaySurface->dumpAsString(surfaceDump);
268     out.append(surfaceDump);
269 }
270 
setSizeForTest(const ui::Size & size)271 void RenderSurface::setSizeForTest(const ui::Size& size) {
272     mSize = size;
273 }
274 
mutableTextureForTest()275 std::shared_ptr<renderengine::ExternalTexture>& RenderSurface::mutableTextureForTest() {
276     return mTexture;
277 }
278 
supportsCompositionStrategyPrediction() const279 bool RenderSurface::supportsCompositionStrategyPrediction() const {
280     return mDisplaySurface->supportsCompositionStrategyPrediction();
281 }
282 
283 } // namespace impl
284 } // namespace android::compositionengine
285