blob: 1ab8dd6ccc7af23551e709c53f1d244e13221382 [file] [log] [blame]
Stan Iliev1a025a72018-09-05 16:35:11 -04001/*
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 "pipeline/skia/LayerDrawable.h"
20#include "renderthread/EglManager.h"
21#include "renderthread/VulkanManager.h"
22
23#include <SkToSRGBColorFilter.h>
24#include <gui/Surface.h>
25#include <ui/Fence.h>
26#include <ui/GraphicBuffer.h>
27#include "DeferredLayerUpdater.h"
28#include "Properties.h"
29#include "hwui/Bitmap.h"
30#include "utils/Color.h"
31#include "utils/MathUtils.h"
John Reck322b8ab2019-03-14 13:15:28 -070032#include "utils/TraceUtils.h"
Stan Iliev1a025a72018-09-05 16:35:11 -040033
34using namespace android::uirenderer::renderthread;
35
36namespace android {
37namespace uirenderer {
38
39CopyResult Readback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) {
40 ATRACE_CALL();
41 // Setup the source
42 sp<GraphicBuffer> sourceBuffer;
43 sp<Fence> sourceFence;
44 Matrix4 texTransform;
45 status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
46 texTransform.invalidateType();
47 if (err != NO_ERROR) {
48 ALOGW("Failed to get last queued buffer, error = %d", err);
49 return CopyResult::UnknownError;
50 }
51 if (!sourceBuffer.get()) {
52 ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
53 return CopyResult::SourceEmpty;
54 }
55 if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
56 ALOGW("Surface is protected, unable to copy from it");
57 return CopyResult::SourceInvalid;
58 }
59 err = sourceFence->wait(500 /* ms */);
60 if (err != NO_ERROR) {
61 ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
62 return CopyResult::Timeout;
63 }
64 if (!sourceBuffer.get()) {
65 return CopyResult::UnknownError;
66 }
67
68 sk_sp<SkColorSpace> colorSpace =
69 DataSpaceToColorSpace(static_cast<android_dataspace>(surface.getBuffersDataSpace()));
Stan Iliev1a025a72018-09-05 16:35:11 -040070 sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer(
Derek Sollenbergerd01b5912018-10-19 15:55:33 -040071 reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()),
72 kPremul_SkAlphaType, colorSpace);
73 return copyImageInto(image, texTransform, srcRect, bitmap);
Stan Iliev1a025a72018-09-05 16:35:11 -040074}
75
76CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {
77 LOG_ALWAYS_FATAL_IF(!hwBitmap->isHardware());
78
79 Rect srcRect;
80 Matrix4 transform;
81 transform.loadScale(1, -1, 1);
82 transform.translate(0, -1);
83
Derek Sollenbergerd01b5912018-10-19 15:55:33 -040084 return copyImageInto(hwBitmap->makeImage(), transform, srcRect, bitmap);
Stan Iliev1a025a72018-09-05 16:35:11 -040085}
86
87CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
88 if (!mRenderThread.getGrContext()) {
89 return CopyResult::UnknownError;
90 }
91
92 // acquire most recent buffer for drawing
93 deferredLayer->updateTexImage();
94 deferredLayer->apply();
95 const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height());
96 CopyResult copyResult = CopyResult::UnknownError;
97 Layer* layer = deferredLayer->backingLayer();
98 if (layer) {
99 if (copyLayerInto(layer, nullptr, &dstRect, bitmap)) {
100 copyResult = CopyResult::Success;
101 }
102 }
103 return copyResult;
104}
105
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400106CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTransform,
Stan Iliev1a025a72018-09-05 16:35:11 -0400107 const Rect& srcRect, SkBitmap* bitmap) {
108 if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
109 mRenderThread.requireGlContext();
110 } else {
Stan Iliev981afe72019-02-13 14:24:33 -0500111 mRenderThread.requireVkContext();
Stan Iliev1a025a72018-09-05 16:35:11 -0400112 }
113 if (!image.get()) {
114 return CopyResult::UnknownError;
115 }
116 int imgWidth = image->width();
117 int imgHeight = image->height();
118 sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
119
120 if (bitmap->colorType() == kRGBA_F16_SkColorType &&
121 !grContext->colorTypeSupportedAsSurface(bitmap->colorType())) {
122 ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
123 return CopyResult::DestinationInvalid;
124 }
125
126 CopyResult copyResult = CopyResult::UnknownError;
127
128 int displayedWidth = imgWidth, displayedHeight = imgHeight;
129 // If this is a 90 or 270 degree rotation we need to swap width/height to get the device
130 // size.
131 if (texTransform[Matrix4::kSkewX] >= 0.5f || texTransform[Matrix4::kSkewX] <= -0.5f) {
132 std::swap(displayedWidth, displayedHeight);
133 }
134 SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
135 SkRect skiaSrcRect = srcRect.toSkRect();
136 if (skiaSrcRect.isEmpty()) {
137 skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight);
138 }
139 bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight));
140 if (!srcNotEmpty) {
141 return copyResult;
142 }
143
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400144 Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc);
Stan Iliev1a025a72018-09-05 16:35:11 -0400145 bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) &&
146 MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
147 layer.setForceFilter(!disableFilter);
148 layer.setSize(displayedWidth, displayedHeight);
149 texTransform.copyTo(layer.getTexTransform());
150 layer.setImage(image);
151 if (copyLayerInto(&layer, &skiaSrcRect, &skiaDestRect, bitmap)) {
152 copyResult = CopyResult::Success;
153 }
154
155 return copyResult;
156}
157
158bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect,
159 SkBitmap* bitmap) {
Stan Iliev1a025a72018-09-05 16:35:11 -0400160 /* This intermediate surface is present to work around a bug in SwiftShader that
161 * prevents us from reading the contents of the layer's texture directly. The
162 * workaround involves first rendering that texture into an intermediate buffer and
163 * then reading from the intermediate buffer into the bitmap.
164 * Another reason to render in an offscreen buffer is to scale and to avoid an issue b/62262733
165 * with reading incorrect data from EGLImage backed SkImage (likely a driver bug).
166 */
167 sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
Derek Sollenbergerf4795f52019-02-06 13:54:12 -0500168 SkBudgeted::kYes, bitmap->info(), 0,
169 kTopLeft_GrSurfaceOrigin, nullptr);
Stan Iliev1a025a72018-09-05 16:35:11 -0400170
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400171 // if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we
172 // attempt to do the intermediate rendering step in 8888
Stan Iliev1a025a72018-09-05 16:35:11 -0400173 if (!tmpSurface.get()) {
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400174 SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
Stan Iliev1a025a72018-09-05 16:35:11 -0400175 tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
Derek Sollenbergerf4795f52019-02-06 13:54:12 -0500176 tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
Stan Iliev1a025a72018-09-05 16:35:11 -0400177 if (!tmpSurface.get()) {
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400178 ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap");
Stan Iliev1a025a72018-09-05 16:35:11 -0400179 return false;
180 }
181 }
182
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400183 if (!skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(),
184 tmpSurface->getCanvas(), layer, srcRect, dstRect,
185 false)) {
186 ALOGW("Unable to draw content from GPU into the provided bitmap");
187 return false;
188 }
Stan Iliev1a025a72018-09-05 16:35:11 -0400189
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400190 if (!tmpSurface->readPixels(*bitmap, 0, 0)) {
191 // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into
192 // 8888 and then convert that into the destination format before giving up.
193 SkBitmap tmpBitmap;
194 SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
195 if (bitmap->info().colorType() == SkColorType::kN32_SkColorType ||
196 !tmpBitmap.tryAllocPixels(tmpInfo) ||
197 !tmpSurface->readPixels(tmpBitmap, 0, 0) ||
198 !tmpBitmap.readPixels(bitmap->info(), bitmap->getPixels(),
199 bitmap->rowBytes(), 0, 0)) {
200 ALOGW("Unable to convert content into the provided bitmap");
201 return false;
Stan Iliev1a025a72018-09-05 16:35:11 -0400202 }
203 }
204
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400205 bitmap->notifyPixelsChanged();
206 return true;
Stan Iliev1a025a72018-09-05 16:35:11 -0400207}
208
209} /* namespace uirenderer */
210} /* namespace android */