• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
23 #include <gl/GrGLInterface.h>
24 #include <gl/GrGLTypes.h>
25 #include <GLES2/gl2.h>
26 #include <GLES2/gl2ext.h>
27 
28 using namespace android::uirenderer::renderthread;
29 
30 namespace android {
31 namespace uirenderer {
32 namespace skiapipeline {
33 
copyImageInto(EGLImageKHR eglImage,const Matrix4 & imgTransform,int imgWidth,int imgHeight,const Rect & srcRect,SkBitmap * bitmap)34 CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
35         int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) {
36 
37     GLuint sourceTexId;
38     glGenTextures(1, &sourceTexId);
39     glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
40     glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);
41 
42     sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
43     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
44         sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
45         LOG_ALWAYS_FATAL_IF(!glInterface.get());
46         grContext.reset(GrContext::Create(GrBackend::kOpenGL_GrBackend,
47                 (GrBackendContext)glInterface.get()));
48     } else {
49         grContext->resetContext();
50     }
51 
52     GrGLTextureInfo externalTexture;
53     externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES;
54     externalTexture.fID = sourceTexId;
55 
56     GrBackendTextureDesc textureDescription;
57     textureDescription.fWidth = imgWidth;
58     textureDescription.fHeight = imgHeight;
59     textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
60     textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
61     textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
62 
63     CopyResult copyResult = CopyResult::UnknownError;
64     sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription));
65     if (image) {
66         SkAutoLockPixels alp(*bitmap);
67 
68         // convert to Skia data structures
69         const SkRect bufferRect = SkRect::MakeIWH(imgWidth, imgHeight);
70         SkRect skiaSrcRect = srcRect.toSkRect();
71         SkMatrix textureMatrix;
72         imgTransform.copyTo(textureMatrix);
73 
74         // remove the y-flip applied to the matrix so that we can scale the srcRect.
75         // This flip is not needed as we specify the origin of the texture when we
76         // wrap it as an SkImage.
77         SkMatrix yFlip = SkMatrix::MakeScale(1, -1);
78         yFlip.postTranslate(0,1);
79         textureMatrix.preConcat(yFlip);
80 
81         // copy the entire src if the rect is empty
82         if (skiaSrcRect.isEmpty()) {
83             skiaSrcRect = bufferRect;
84         }
85 
86         // since the y-flip has been removed we can simply scale & translate
87         // the source rectangle
88         textureMatrix.mapRect(&skiaSrcRect);
89 
90         if (skiaSrcRect.intersect(bufferRect)) {
91             SkPoint srcOrigin = SkPoint::Make(skiaSrcRect.fLeft, skiaSrcRect.fTop);
92 
93             // if we need to scale the result we must render to an offscreen buffer
94             if (bitmap->width() != skiaSrcRect.width()
95                     || bitmap->height() != skiaSrcRect.height()) {
96                 sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget(
97                         grContext.get(), SkBudgeted::kYes, bitmap->info());
98                 SkPaint paint;
99                 paint.setBlendMode(SkBlendMode::kSrc);
100                 scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect,
101                         SkRect::MakeWH(bitmap->width(), bitmap->height()), &paint);
102                 image = scaledSurface->makeImageSnapshot();
103                 srcOrigin.set(0,0);
104             }
105 
106             if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
107                                   srcOrigin.fX, srcOrigin.fY)) {
108                 copyResult = CopyResult::Success;
109             }
110         }
111     }
112 
113     // make sure that we have deleted the texture (in the SkImage) before we
114     // destroy the EGLImage that it was created from
115     image.reset();
116     return copyResult;
117 }
118 
119 } /* namespace skiapipeline */
120 } /* namespace uirenderer */
121 } /* namespace android */
122