• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 #include "Readback.h"
18 
19 #include <sync/sync.h>
20 #include <system/window.h>
21 #include <ui/GraphicBuffer.h>
22 
23 #include "DeferredLayerUpdater.h"
24 #include "Properties.h"
25 #include "hwui/Bitmap.h"
26 #include "pipeline/skia/LayerDrawable.h"
27 #include "renderthread/EglManager.h"
28 #include "renderthread/VulkanManager.h"
29 #include "utils/Color.h"
30 #include "utils/MathUtils.h"
31 #include "utils/TraceUtils.h"
32 
33 using namespace android::uirenderer::renderthread;
34 
35 namespace android {
36 namespace uirenderer {
37 
copySurfaceInto(ANativeWindow * window,const Rect & srcRect,SkBitmap * bitmap)38 CopyResult Readback::copySurfaceInto(ANativeWindow* window, const Rect& srcRect, SkBitmap* bitmap) {
39     ATRACE_CALL();
40     // Setup the source
41     AHardwareBuffer* rawSourceBuffer;
42     int rawSourceFence;
43     Matrix4 texTransform;
44     status_t err = ANativeWindow_getLastQueuedBuffer(window, &rawSourceBuffer, &rawSourceFence,
45                                                      texTransform.data);
46     base::unique_fd sourceFence(rawSourceFence);
47     texTransform.invalidateType();
48     if (err != NO_ERROR) {
49         ALOGW("Failed to get last queued buffer, error = %d", err);
50         return CopyResult::UnknownError;
51     }
52     if (rawSourceBuffer == nullptr) {
53         ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
54         return CopyResult::SourceEmpty;
55     }
56 
57     std::unique_ptr<AHardwareBuffer, decltype(&AHardwareBuffer_release)> sourceBuffer(
58             rawSourceBuffer, AHardwareBuffer_release);
59     AHardwareBuffer_Desc description;
60     AHardwareBuffer_describe(sourceBuffer.get(), &description);
61     if (description.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
62         ALOGW("Surface is protected, unable to copy from it");
63         return CopyResult::SourceInvalid;
64     }
65 
66     if (sourceFence != -1 && sync_wait(sourceFence.get(), 500 /* ms */) != NO_ERROR) {
67         ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
68         return CopyResult::Timeout;
69     }
70 
71     sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(
72             static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(window)));
73     sk_sp<SkImage> image =
74             SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace);
75     return copyImageInto(image, texTransform, srcRect, bitmap);
76 }
77 
copyHWBitmapInto(Bitmap * hwBitmap,SkBitmap * bitmap)78 CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {
79     LOG_ALWAYS_FATAL_IF(!hwBitmap->isHardware());
80 
81     Rect srcRect;
82     Matrix4 transform;
83     transform.loadScale(1, -1, 1);
84     transform.translate(0, -1);
85 
86     return copyImageInto(hwBitmap->makeImage(), transform, srcRect, bitmap);
87 }
88 
copyLayerInto(DeferredLayerUpdater * deferredLayer,SkBitmap * bitmap)89 CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
90     ATRACE_CALL();
91     if (!mRenderThread.getGrContext()) {
92         return CopyResult::UnknownError;
93     }
94 
95     // acquire most recent buffer for drawing
96     deferredLayer->updateTexImage();
97     deferredLayer->apply();
98     const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height());
99     CopyResult copyResult = CopyResult::UnknownError;
100     Layer* layer = deferredLayer->backingLayer();
101     if (layer) {
102         if (copyLayerInto(layer, nullptr, &dstRect, bitmap)) {
103             copyResult = CopyResult::Success;
104         }
105     }
106     return copyResult;
107 }
108 
copyImageInto(const sk_sp<SkImage> & image,Matrix4 & texTransform,const Rect & srcRect,SkBitmap * bitmap)109 CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform,
110                                    const Rect& srcRect, SkBitmap* bitmap) {
111     ATRACE_CALL();
112     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
113         mRenderThread.requireGlContext();
114     } else {
115         mRenderThread.requireVkContext();
116     }
117     if (!image.get()) {
118         return CopyResult::UnknownError;
119     }
120     int imgWidth = image->width();
121     int imgHeight = image->height();
122     sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
123 
124     if (bitmap->colorType() == kRGBA_F16_SkColorType &&
125         !grContext->colorTypeSupportedAsSurface(bitmap->colorType())) {
126         ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
127         return CopyResult::DestinationInvalid;
128     }
129 
130     CopyResult copyResult = CopyResult::UnknownError;
131 
132     int displayedWidth = imgWidth, displayedHeight = imgHeight;
133     // If this is a 90 or 270 degree rotation we need to swap width/height to get the device
134     // size.
135     if (texTransform[Matrix4::kSkewX] >= 0.5f || texTransform[Matrix4::kSkewX] <= -0.5f) {
136         std::swap(displayedWidth, displayedHeight);
137     }
138     SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
139     SkRect skiaSrcRect = srcRect.toSkRect();
140     if (skiaSrcRect.isEmpty()) {
141         skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight);
142     }
143     bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight));
144     if (!srcNotEmpty) {
145         return copyResult;
146     }
147 
148     Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc);
149     layer.setSize(displayedWidth, displayedHeight);
150     texTransform.copyTo(layer.getTexTransform());
151     layer.setImage(image);
152     // Scaling filter is not explicitly set here, because it is done inside copyLayerInfo
153     // after checking the necessity based on the src/dest rect size and the transformation.
154     if (copyLayerInto(&layer, &skiaSrcRect, &skiaDestRect, bitmap)) {
155         copyResult = CopyResult::Success;
156     }
157 
158     return copyResult;
159 }
160 
copyLayerInto(Layer * layer,const SkRect * srcRect,const SkRect * dstRect,SkBitmap * bitmap)161 bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect,
162                              SkBitmap* bitmap) {
163     /* This intermediate surface is present to work around a bug in SwiftShader that
164      * prevents us from reading the contents of the layer's texture directly. The
165      * workaround involves first rendering that texture into an intermediate buffer and
166      * then reading from the intermediate buffer into the bitmap.
167      * Another reason to render in an offscreen buffer is to scale and to avoid an issue b/62262733
168      * with reading incorrect data from EGLImage backed SkImage (likely a driver bug).
169      */
170     sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
171                                                               SkBudgeted::kYes, bitmap->info(), 0,
172                                                               kTopLeft_GrSurfaceOrigin, nullptr);
173 
174     // if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we
175     // attempt to do the intermediate rendering step in 8888
176     if (!tmpSurface.get()) {
177         SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
178         tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
179                                                  tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
180         if (!tmpSurface.get()) {
181             ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap");
182             return false;
183         }
184     }
185 
186     if (!skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(),
187                                                 tmpSurface->getCanvas(), layer, srcRect, dstRect,
188                                                 false)) {
189         ALOGW("Unable to draw content from GPU into the provided bitmap");
190         return false;
191     }
192 
193     if (!tmpSurface->readPixels(*bitmap, 0, 0)) {
194         // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into
195         // 8888 and then convert that into the destination format before giving up.
196         SkBitmap tmpBitmap;
197         SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
198         if (bitmap->info().colorType() == SkColorType::kN32_SkColorType ||
199                 !tmpBitmap.tryAllocPixels(tmpInfo) ||
200                 !tmpSurface->readPixels(tmpBitmap, 0, 0) ||
201                 !tmpBitmap.readPixels(bitmap->info(), bitmap->getPixels(),
202                                       bitmap->rowBytes(), 0, 0)) {
203             ALOGW("Unable to convert content into the provided bitmap");
204             return false;
205         }
206     }
207 
208     bitmap->notifyPixelsChanged();
209     return true;
210 }
211 
212 } /* namespace uirenderer */
213 } /* namespace android */
214