• 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 
22 #include <gui/TraceUtils.h>
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/NdkUtils.h"
32 
33 using namespace android::uirenderer::renderthread;
34 
35 namespace android {
36 namespace uirenderer {
37 
38 #define ARECT_ARGS(r) float((r).left), float((r).top), float((r).right), float((r).bottom)
39 
copySurfaceInto(ANativeWindow * window,const Rect & inSrcRect,SkBitmap * bitmap)40 CopyResult Readback::copySurfaceInto(ANativeWindow* window, const Rect& inSrcRect,
41                                      SkBitmap* bitmap) {
42     ATRACE_CALL();
43     // Setup the source
44     AHardwareBuffer* rawSourceBuffer;
45     int rawSourceFence;
46     ARect cropRect;
47     uint32_t windowTransform;
48     status_t err = ANativeWindow_getLastQueuedBuffer2(window, &rawSourceBuffer, &rawSourceFence,
49                                                       &cropRect, &windowTransform);
50     base::unique_fd sourceFence(rawSourceFence);
51     // Really this shouldn't ever happen, but better safe than sorry.
52     if (err == UNKNOWN_TRANSACTION) {
53         ALOGW("Readback failed to ANativeWindow_getLastQueuedBuffer2 - who are we talking to?");
54         return copySurfaceIntoLegacy(window, inSrcRect, bitmap);
55     }
56     ALOGV("Using new path, cropRect=" RECT_STRING ", transform=%x", ARECT_ARGS(cropRect),
57           windowTransform);
58 
59     if (err != NO_ERROR) {
60         ALOGW("Failed to get last queued buffer, error = %d", err);
61         return CopyResult::UnknownError;
62     }
63     if (rawSourceBuffer == nullptr) {
64         ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
65         return CopyResult::SourceEmpty;
66     }
67     UniqueAHardwareBuffer sourceBuffer{rawSourceBuffer};
68     AHardwareBuffer_Desc description;
69     AHardwareBuffer_describe(sourceBuffer.get(), &description);
70     if (description.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
71         ALOGW("Surface is protected, unable to copy from it");
72         return CopyResult::SourceInvalid;
73     }
74 
75     if (sourceFence != -1 && sync_wait(sourceFence.get(), 500 /* ms */) != NO_ERROR) {
76         ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
77         return CopyResult::Timeout;
78     }
79 
80     sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(
81             static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(window)));
82     sk_sp<SkImage> image =
83             SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace);
84 
85     if (!image.get()) {
86         return CopyResult::UnknownError;
87     }
88 
89     sk_sp<GrDirectContext> grContext = mRenderThread.requireGrContext();
90 
91     SkRect srcRect = inSrcRect.toSkRect();
92 
93     SkRect imageSrcRect =
94             SkRect::MakeLTRB(cropRect.left, cropRect.top, cropRect.right, cropRect.bottom);
95     if (imageSrcRect.isEmpty()) {
96         imageSrcRect = SkRect::MakeIWH(description.width, description.height);
97     }
98     ALOGV("imageSrcRect = " RECT_STRING, SK_RECT_ARGS(imageSrcRect));
99 
100     // Represents the "logical" width/height of the texture. That is, the dimensions of the buffer
101     // after respecting crop & rotate. flipV/flipH still result in the same width & height
102     // so we can ignore those for this.
103     const SkRect textureRect =
104             (windowTransform & NATIVE_WINDOW_TRANSFORM_ROT_90)
105                     ? SkRect::MakeIWH(imageSrcRect.height(), imageSrcRect.width())
106                     : SkRect::MakeIWH(imageSrcRect.width(), imageSrcRect.height());
107 
108     if (srcRect.isEmpty()) {
109         srcRect = textureRect;
110     } else {
111         ALOGV("intersecting " RECT_STRING " with " RECT_STRING, SK_RECT_ARGS(srcRect),
112               SK_RECT_ARGS(textureRect));
113         if (!srcRect.intersect(textureRect)) {
114             return CopyResult::UnknownError;
115         }
116     }
117 
118     sk_sp<SkSurface> tmpSurface =
119             SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
120                                         bitmap->info(), 0, kTopLeft_GrSurfaceOrigin, nullptr);
121 
122     // if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we
123     // attempt to do the intermediate rendering step in 8888
124     if (!tmpSurface.get()) {
125         SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
126         tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
127                                                  tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
128         if (!tmpSurface.get()) {
129             ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap");
130             return CopyResult::UnknownError;
131         }
132     }
133 
134     /*
135      * The grand ordering of events.
136      * First we apply the buffer's crop, done by using a srcRect of the crop with a dstRect of the
137      * same width/height as the srcRect but with a 0x0 origin
138      *
139      * Second we apply the window transform via a Canvas matrix. Ordering for that is as follows:
140      *  1) FLIP_H
141      *  2) FLIP_V
142      *  3) ROT_90
143      * as per GLConsumer::computeTransformMatrix
144      *
145      * Third we apply the user's supplied cropping & scale to the output by doing a RectToRect
146      * matrix transform from srcRect to {0,0, bitmapWidth, bitmapHeight}
147      *
148      * Finally we're done messing with this bloody thing for hopefully the last time.
149      *
150      * That's a lie since...
151      * TODO: Do all this same stuff for TextureView as it's strictly more correct & easier
152      * to rationalize. And we can fix the 1-px crop bug.
153      */
154 
155     SkMatrix m;
156     const SkRect imageDstRect = SkRect::MakeIWH(imageSrcRect.width(), imageSrcRect.height());
157     const float px = imageDstRect.centerX();
158     const float py = imageDstRect.centerY();
159     if (windowTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
160         m.postScale(-1.f, 1.f, px, py);
161     }
162     if (windowTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
163         m.postScale(1.f, -1.f, px, py);
164     }
165     if (windowTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
166         m.postRotate(90, 0, 0);
167         m.postTranslate(imageDstRect.height(), 0);
168     }
169 
170     SkSamplingOptions sampling(SkFilterMode::kNearest);
171     ALOGV("Mapping from " RECT_STRING " to " RECT_STRING, SK_RECT_ARGS(srcRect),
172           SK_RECT_ARGS(SkRect::MakeWH(bitmap->width(), bitmap->height())));
173     m.postConcat(SkMatrix::MakeRectToRect(srcRect,
174                                           SkRect::MakeWH(bitmap->width(), bitmap->height()),
175                                           SkMatrix::kFill_ScaleToFit));
176     if (srcRect.width() != bitmap->width() || srcRect.height() != bitmap->height()) {
177         sampling = SkSamplingOptions(SkFilterMode::kLinear);
178     }
179 
180     SkCanvas* canvas = tmpSurface->getCanvas();
181     canvas->save();
182     canvas->concat(m);
183     SkPaint paint;
184     paint.setAlpha(255);
185     paint.setBlendMode(SkBlendMode::kSrc);
186     const bool hasBufferCrop = cropRect.left < cropRect.right && cropRect.top < cropRect.bottom;
187     auto constraint =
188             hasBufferCrop ? SkCanvas::kStrict_SrcRectConstraint : SkCanvas::kFast_SrcRectConstraint;
189     canvas->drawImageRect(image, imageSrcRect, imageDstRect, sampling, &paint, constraint);
190     canvas->restore();
191 
192     if (!tmpSurface->readPixels(*bitmap, 0, 0)) {
193         // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into
194         // 8888 and then convert that into the destination format before giving up.
195         SkBitmap tmpBitmap;
196         SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
197         if (bitmap->info().colorType() == SkColorType::kN32_SkColorType ||
198             !tmpBitmap.tryAllocPixels(tmpInfo) || !tmpSurface->readPixels(tmpBitmap, 0, 0) ||
199             !tmpBitmap.readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
200             ALOGW("Unable to convert content into the provided bitmap");
201             return CopyResult::UnknownError;
202         }
203     }
204 
205     bitmap->notifyPixelsChanged();
206 
207     return CopyResult::Success;
208 }
209 
copySurfaceIntoLegacy(ANativeWindow * window,const Rect & srcRect,SkBitmap * bitmap)210 CopyResult Readback::copySurfaceIntoLegacy(ANativeWindow* window, const Rect& srcRect,
211                                            SkBitmap* bitmap) {
212     // Setup the source
213     AHardwareBuffer* rawSourceBuffer;
214     int rawSourceFence;
215     Matrix4 texTransform;
216     status_t err = ANativeWindow_getLastQueuedBuffer(window, &rawSourceBuffer, &rawSourceFence,
217                                                      texTransform.data);
218     base::unique_fd sourceFence(rawSourceFence);
219     texTransform.invalidateType();
220     if (err != NO_ERROR) {
221         ALOGW("Failed to get last queued buffer, error = %d", err);
222         return CopyResult::UnknownError;
223     }
224     if (rawSourceBuffer == nullptr) {
225         ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
226         return CopyResult::SourceEmpty;
227     }
228 
229     UniqueAHardwareBuffer sourceBuffer{rawSourceBuffer};
230     AHardwareBuffer_Desc description;
231     AHardwareBuffer_describe(sourceBuffer.get(), &description);
232     if (description.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
233         ALOGW("Surface is protected, unable to copy from it");
234         return CopyResult::SourceInvalid;
235     }
236 
237     if (sourceFence != -1 && sync_wait(sourceFence.get(), 500 /* ms */) != NO_ERROR) {
238         ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
239         return CopyResult::Timeout;
240     }
241 
242     sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(
243             static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(window)));
244     sk_sp<SkImage> image =
245             SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace);
246     return copyImageInto(image, texTransform, srcRect, bitmap);
247 }
248 
copyHWBitmapInto(Bitmap * hwBitmap,SkBitmap * bitmap)249 CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {
250     LOG_ALWAYS_FATAL_IF(!hwBitmap->isHardware());
251 
252     Rect srcRect;
253     Matrix4 transform;
254     transform.loadScale(1, -1, 1);
255     transform.translate(0, -1);
256 
257     return copyImageInto(hwBitmap->makeImage(), transform, srcRect, bitmap);
258 }
259 
copyLayerInto(DeferredLayerUpdater * deferredLayer,SkBitmap * bitmap)260 CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
261     ATRACE_CALL();
262     if (!mRenderThread.getGrContext()) {
263         return CopyResult::UnknownError;
264     }
265 
266     // acquire most recent buffer for drawing
267     deferredLayer->updateTexImage();
268     deferredLayer->apply();
269     const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height());
270     CopyResult copyResult = CopyResult::UnknownError;
271     Layer* layer = deferredLayer->backingLayer();
272     if (layer) {
273         if (copyLayerInto(layer, nullptr, &dstRect, bitmap)) {
274             copyResult = CopyResult::Success;
275         }
276     }
277     return copyResult;
278 }
279 
copyImageInto(const sk_sp<SkImage> & image,SkBitmap * bitmap)280 CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, SkBitmap* bitmap) {
281     Rect srcRect;
282     Matrix4 transform;
283     transform.loadScale(1, -1, 1);
284     transform.translate(0, -1);
285     return copyImageInto(image, transform, srcRect, bitmap);
286 }
287 
copyImageInto(const sk_sp<SkImage> & image,Matrix4 & texTransform,const Rect & srcRect,SkBitmap * bitmap)288 CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform,
289                                    const Rect& srcRect, SkBitmap* bitmap) {
290     ATRACE_CALL();
291     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
292         mRenderThread.requireGlContext();
293     } else {
294         mRenderThread.requireVkContext();
295     }
296     if (!image.get()) {
297         return CopyResult::UnknownError;
298     }
299     int imgWidth = image->width();
300     int imgHeight = image->height();
301     sk_sp<GrDirectContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
302 
303     CopyResult copyResult = CopyResult::UnknownError;
304 
305     int displayedWidth = imgWidth, displayedHeight = imgHeight;
306     // If this is a 90 or 270 degree rotation we need to swap width/height to get the device
307     // size.
308     if (texTransform[Matrix4::kSkewX] >= 0.5f || texTransform[Matrix4::kSkewX] <= -0.5f) {
309         std::swap(displayedWidth, displayedHeight);
310     }
311     SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
312     SkRect skiaSrcRect = srcRect.toSkRect();
313     if (skiaSrcRect.isEmpty()) {
314         skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight);
315     }
316     bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight));
317     if (!srcNotEmpty) {
318         return copyResult;
319     }
320 
321     Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc);
322     layer.setSize(displayedWidth, displayedHeight);
323     texTransform.copyTo(layer.getTexTransform());
324     layer.setImage(image);
325     // Scaling filter is not explicitly set here, because it is done inside copyLayerInfo
326     // after checking the necessity based on the src/dest rect size and the transformation.
327     if (copyLayerInto(&layer, &skiaSrcRect, &skiaDestRect, bitmap)) {
328         copyResult = CopyResult::Success;
329     }
330 
331     return copyResult;
332 }
333 
copyLayerInto(Layer * layer,const SkRect * srcRect,const SkRect * dstRect,SkBitmap * bitmap)334 bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect,
335                              SkBitmap* bitmap) {
336     /* This intermediate surface is present to work around limitations that LayerDrawable expects
337      * to render into a GPU backed canvas.  Additionally, the offscreen buffer solution works around
338      * a scaling issue (b/62262733) that was encountered when sampling from an EGLImage into a
339      * software buffer.
340      */
341     sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
342                                                               SkBudgeted::kYes, bitmap->info(), 0,
343                                                               kTopLeft_GrSurfaceOrigin, nullptr);
344 
345     // if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we
346     // attempt to do the intermediate rendering step in 8888
347     if (!tmpSurface.get()) {
348         SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
349         tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
350                                                  tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
351         if (!tmpSurface.get()) {
352             ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap");
353             return false;
354         }
355     }
356 
357     if (!skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(),
358                                                 tmpSurface->getCanvas(), layer, srcRect, dstRect,
359                                                 false)) {
360         ALOGW("Unable to draw content from GPU into the provided bitmap");
361         return false;
362     }
363 
364     if (!tmpSurface->readPixels(*bitmap, 0, 0)) {
365         // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into
366         // 8888 and then convert that into the destination format before giving up.
367         SkBitmap tmpBitmap;
368         SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
369         if (bitmap->info().colorType() == SkColorType::kN32_SkColorType ||
370                 !tmpBitmap.tryAllocPixels(tmpInfo) ||
371                 !tmpSurface->readPixels(tmpBitmap, 0, 0) ||
372                 !tmpBitmap.readPixels(bitmap->info(), bitmap->getPixels(),
373                                       bitmap->rowBytes(), 0, 0)) {
374             ALOGW("Unable to convert content into the provided bitmap");
375             return false;
376         }
377     }
378 
379     bitmap->notifyPixelsChanged();
380     return true;
381 }
382 
383 } /* namespace uirenderer */
384 } /* namespace android */
385