blob: 0760f16108915dc46140646aed64274146b98855 [file] [log] [blame]
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -05001/*
2 * Copyright (C) 2016 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 "SkiaOpenGLReadback.h"
18
John Reck1bcacfd2017-11-03 10:12:19 -070019#include <GLES2/gl2.h>
20#include <GLES2/gl2ext.h>
21#include <GrBackendSurface.h>
22#include <SkCanvas.h>
23#include <SkSurface.h>
24#include <gl/GrGLInterface.h>
25#include <gl/GrGLTypes.h>
Derek Sollenberger4170db32017-08-09 13:52:36 -040026#include "DeviceInfo.h"
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050027#include "Matrix.h"
28#include "Properties.h"
Stan Ilievd50edd02018-06-22 17:33:43 -040029#include "utils/MathUtils.h"
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050030
31using namespace android::uirenderer::renderthread;
32
33namespace android {
34namespace uirenderer {
35namespace skiapipeline {
36
37CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
John Reck1bcacfd2017-11-03 10:12:19 -070038 int imgWidth, int imgHeight, const Rect& srcRect,
39 SkBitmap* bitmap) {
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050040 GLuint sourceTexId;
41 glGenTextures(1, &sourceTexId);
42 glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
43 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);
44
45 sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
46 if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
47 sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
48 LOG_ALWAYS_FATAL_IF(!glInterface.get());
Greg Daniel660d6ec2017-12-08 11:44:27 -050049 grContext = GrContext::MakeGL(std::move(glInterface));
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050050 } else {
51 grContext->resetContext();
52 }
53
54 GrGLTextureInfo externalTexture;
55 externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES;
56 externalTexture.fID = sourceTexId;
57
Stan Iliev08fc19a2017-07-24 10:20:33 -040058 GrPixelConfig pixelConfig;
59 switch (bitmap->colorType()) {
John Reck1bcacfd2017-11-03 10:12:19 -070060 case kRGBA_F16_SkColorType:
61 pixelConfig = kRGBA_half_GrPixelConfig;
62 break;
63 case kN32_SkColorType:
64 default:
65 pixelConfig = kRGBA_8888_GrPixelConfig;
66 break;
Stan Iliev08fc19a2017-07-24 10:20:33 -040067 }
68
Derek Sollenberger4170db32017-08-09 13:52:36 -040069 if (pixelConfig == kRGBA_half_GrPixelConfig &&
Stan Ilievf1f3c382017-11-09 12:17:35 -050070 !grContext->caps()->isConfigRenderable(kRGBA_half_GrPixelConfig, false)) {
Derek Sollenberger4170db32017-08-09 13:52:36 -040071 ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
72 return CopyResult::DestinationInvalid;
73 }
74
Stan Iliev08fc19a2017-07-24 10:20:33 -040075 GrBackendTexture backendTexture(imgWidth, imgHeight, pixelConfig, externalTexture);
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050076
77 CopyResult copyResult = CopyResult::UnknownError;
Greg Danielac2d2322017-07-12 11:30:15 -040078 sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
John Reck1bcacfd2017-11-03 10:12:19 -070079 kTopLeft_GrSurfaceOrigin));
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050080 if (image) {
Stan Ilievcf917882017-10-27 19:29:44 -040081 int displayedWidth = imgWidth, displayedHeight = imgHeight;
82 // If this is a 90 or 270 degree rotation we need to swap width/height to get the device
83 // size.
84 if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
85 std::swap(displayedWidth, displayedHeight);
Stan Iliev1220a2a2017-07-19 18:09:25 -040086 }
Stan Ilievdf6520e2017-07-17 18:50:16 -040087 SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height());
Stan Ilievcf917882017-10-27 19:29:44 -040088 SkRect skiaSrcRect = srcRect.toSkRect();
89 if (skiaSrcRect.isEmpty()) {
90 skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight);
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050091 }
Stan Ilievcf917882017-10-27 19:29:44 -040092 bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight));
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050093
Stan Ilievdf6520e2017-07-17 18:50:16 -040094 if (srcNotEmpty) {
Stan Ilievcf917882017-10-27 19:29:44 -040095 SkMatrix textureMatrixInv;
96 imgTransform.copyTo(textureMatrixInv);
John Reck1bcacfd2017-11-03 10:12:19 -070097 // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
Stan Ilievcf917882017-10-27 19:29:44 -040098 // use bottom left origin and remove flipV and invert transformations.
99 SkMatrix flipV;
100 flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
101 textureMatrixInv.preConcat(flipV);
John Reck1bcacfd2017-11-03 10:12:19 -0700102 textureMatrixInv.preScale(1.0f / displayedWidth, 1.0f / displayedHeight);
Stan Ilievcf917882017-10-27 19:29:44 -0400103 textureMatrixInv.postScale(imgWidth, imgHeight);
104 SkMatrix textureMatrix;
105 if (!textureMatrixInv.invert(&textureMatrix)) {
106 textureMatrix = textureMatrixInv;
107 }
108
109 textureMatrixInv.mapRect(&skiaSrcRect);
110 textureMatrixInv.mapRect(&skiaDestRect);
111
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400112 // we render in an offscreen buffer to scale and to avoid an issue b/62262733
113 // with reading incorrect data from EGLImage backed SkImage (likely a driver bug)
John Reck1bcacfd2017-11-03 10:12:19 -0700114 sk_sp<SkSurface> scaledSurface =
115 SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kYes, bitmap->info());
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400116 SkPaint paint;
117 paint.setBlendMode(SkBlendMode::kSrc);
Stan Ilievcf917882017-10-27 19:29:44 -0400118 // Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage
119 // is codified by tests using golden images like DecodeAccuracyTest.
Stan Ilievd50edd02018-06-22 17:33:43 -0400120 bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width())
121 && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
122 if (!disableFilter) {
Stan Ilievcf917882017-10-27 19:29:44 -0400123 paint.setFilterQuality(kLow_SkFilterQuality);
124 }
Stan Ilievdf6520e2017-07-17 18:50:16 -0400125 scaledSurface->getCanvas()->concat(textureMatrix);
Derek Sollenberger6c2a9e22017-08-15 16:23:01 -0400126 scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint,
John Reck1bcacfd2017-11-03 10:12:19 -0700127 SkCanvas::kFast_SrcRectConstraint);
Stan Ilievdf6520e2017-07-17 18:50:16 -0400128
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400129 image = scaledSurface->makeImageSnapshot();
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500130
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400131 if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
John Reckabbedfc2017-07-06 15:27:23 -0700132 bitmap->notifyPixelsChanged();
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -0500133 copyResult = CopyResult::Success;
134 }
135 }
136 }
137
138 // make sure that we have deleted the texture (in the SkImage) before we
139 // destroy the EGLImage that it was created from
140 image.reset();
141 return copyResult;
142}
143
144} /* namespace skiapipeline */
145} /* namespace uirenderer */
146} /* namespace android */