blob: 69b9c01fe023e5fda851e3b21a81bab47537446f [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
19#include "Matrix.h"
20#include "Properties.h"
21#include <SkCanvas.h>
22#include <SkSurface.h>
Greg Danielac2d2322017-07-12 11:30:15 -040023#include <GrBackendSurface.h>
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050024#include <gl/GrGLInterface.h>
25#include <gl/GrGLTypes.h>
26#include <GLES2/gl2.h>
27#include <GLES2/gl2ext.h>
28
29using namespace android::uirenderer::renderthread;
30
31namespace android {
32namespace uirenderer {
33namespace skiapipeline {
34
35CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
36 int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) {
37
38 GLuint sourceTexId;
39 glGenTextures(1, &sourceTexId);
40 glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
41 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);
42
43 sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
44 if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
45 sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
46 LOG_ALWAYS_FATAL_IF(!glInterface.get());
47 grContext.reset(GrContext::Create(GrBackend::kOpenGL_GrBackend,
48 (GrBackendContext)glInterface.get()));
49 } else {
50 grContext->resetContext();
51 }
52
53 GrGLTextureInfo externalTexture;
54 externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES;
55 externalTexture.fID = sourceTexId;
56
Greg Danielac2d2322017-07-12 11:30:15 -040057 GrBackendTexture backendTexture(imgWidth, imgHeight, kRGBA_8888_GrPixelConfig, externalTexture);
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050058
59 CopyResult copyResult = CopyResult::UnknownError;
Greg Danielac2d2322017-07-12 11:30:15 -040060 sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
61 kTopLeft_GrSurfaceOrigin));
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050062 if (image) {
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050063 // convert to Skia data structures
64 const SkRect bufferRect = SkRect::MakeIWH(imgWidth, imgHeight);
65 SkRect skiaSrcRect = srcRect.toSkRect();
66 SkMatrix textureMatrix;
67 imgTransform.copyTo(textureMatrix);
68
69 // remove the y-flip applied to the matrix so that we can scale the srcRect.
70 // This flip is not needed as we specify the origin of the texture when we
71 // wrap it as an SkImage.
72 SkMatrix yFlip = SkMatrix::MakeScale(1, -1);
73 yFlip.postTranslate(0,1);
74 textureMatrix.preConcat(yFlip);
75
76 // copy the entire src if the rect is empty
77 if (skiaSrcRect.isEmpty()) {
78 skiaSrcRect = bufferRect;
79 }
80
81 // since the y-flip has been removed we can simply scale & translate
82 // the source rectangle
83 textureMatrix.mapRect(&skiaSrcRect);
84
85 if (skiaSrcRect.intersect(bufferRect)) {
Stan Iliev7bc3bc62017-05-24 13:28:36 -040086 // we render in an offscreen buffer to scale and to avoid an issue b/62262733
87 // with reading incorrect data from EGLImage backed SkImage (likely a driver bug)
88 sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget(
89 grContext.get(), SkBudgeted::kYes, bitmap->info());
90 SkPaint paint;
91 paint.setBlendMode(SkBlendMode::kSrc);
92 scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect,
93 SkRect::MakeWH(bitmap->width(), bitmap->height()), &paint);
94 image = scaledSurface->makeImageSnapshot();
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050095
Stan Iliev7bc3bc62017-05-24 13:28:36 -040096 if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
John Reckabbedfc2017-07-06 15:27:23 -070097 bitmap->notifyPixelsChanged();
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050098 copyResult = CopyResult::Success;
99 }
100 }
101 }
102
103 // make sure that we have deleted the texture (in the SkImage) before we
104 // destroy the EGLImage that it was created from
105 image.reset();
106 return copyResult;
107}
108
109} /* namespace skiapipeline */
110} /* namespace uirenderer */
111} /* namespace android */