SkiaOpenGLReadback.cpp revision 576b6a8a7994f649c0dbacfc34611d1580e16bd6
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 28using namespace android::uirenderer::renderthread; 29 30namespace android { 31namespace uirenderer { 32namespace skiapipeline { 33 34CopyResult 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