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 <GrBackendSurface.h> 24 #include <gl/GrGLInterface.h> 25 #include <gl/GrGLTypes.h> 26 #include <GLES2/gl2.h> 27 #include <GLES2/gl2ext.h> 28 29 using namespace android::uirenderer::renderthread; 30 31 namespace android { 32 namespace uirenderer { 33 namespace skiapipeline { 34 35 CopyResult 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 57 GrBackendTexture backendTexture(imgWidth, imgHeight, kRGBA_8888_GrPixelConfig, externalTexture); 58 59 CopyResult copyResult = CopyResult::UnknownError; 60 sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture, 61 kTopLeft_GrSurfaceOrigin)); 62 if (image) { 63 SkMatrix textureMatrix; 64 imgTransform.copyTo(textureMatrix); 65 66 // remove the y-flip applied to the matrix 67 SkMatrix yFlip = SkMatrix::MakeScale(1, -1); 68 yFlip.postTranslate(0,1); 69 textureMatrix.preConcat(yFlip); 70 71 // multiply by image size, because textureMatrix maps to [0..1] range 72 textureMatrix[SkMatrix::kMTransX] *= imgWidth; 73 textureMatrix[SkMatrix::kMTransY] *= imgHeight; 74 75 // swap rotation and translation part of the matrix, because we convert from 76 // right-handed Cartesian to left-handed coordinate system. 77 std::swap(textureMatrix[SkMatrix::kMTransX], textureMatrix[SkMatrix::kMTransY]); 78 std::swap(textureMatrix[SkMatrix::kMSkewX], textureMatrix[SkMatrix::kMSkewY]); 79 80 // convert to Skia data structures 81 SkRect skiaSrcRect = srcRect.toSkRect(); 82 SkMatrix textureMatrixInv; 83 SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height()); 84 bool srcNotEmpty = false; 85 if (textureMatrix.invert(&textureMatrixInv)) { 86 if (skiaSrcRect.isEmpty()) { 87 skiaSrcRect = SkRect::MakeIWH(imgWidth, imgHeight); 88 srcNotEmpty = !skiaSrcRect.isEmpty(); 89 } else { 90 // src and dest rectangles need to be converted into texture coordinates before the 91 // rotation matrix is applied (because drawImageRect preconcat its matrix). 92 textureMatrixInv.mapRect(&skiaSrcRect); 93 srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(imgWidth, imgHeight)); 94 } 95 textureMatrixInv.mapRect(&skiaDestRect); 96 } 97 98 if (srcNotEmpty) { 99 // we render in an offscreen buffer to scale and to avoid an issue b/62262733 100 // with reading incorrect data from EGLImage backed SkImage (likely a driver bug) 101 sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget( 102 grContext.get(), SkBudgeted::kYes, bitmap->info()); 103 SkPaint paint; 104 paint.setBlendMode(SkBlendMode::kSrc); 105 scaledSurface->getCanvas()->concat(textureMatrix); 106 scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint); 107 108 image = scaledSurface->makeImageSnapshot(); 109 110 if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { 111 bitmap->notifyPixelsChanged(); 112 copyResult = CopyResult::Success; 113 } 114 } 115 } 116 117 // make sure that we have deleted the texture (in the SkImage) before we 118 // destroy the EGLImage that it was created from 119 image.reset(); 120 return copyResult; 121 } 122 123 } /* namespace skiapipeline */ 124 } /* namespace uirenderer */ 125 } /* namespace android */ 126