SkiaOpenGLReadback.cpp revision 625dd56a45bfe95c5f1baa1891529503ff3374a9
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 // TODO: add color correctness - pass null color space for now 65 sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription)); 66 if (image) { 67 SkAutoLockPixels alp(*bitmap); 68 69 // convert to Skia data structures 70 const SkRect bufferRect = SkRect::MakeIWH(imgWidth, imgHeight); 71 SkRect skiaSrcRect = srcRect.toSkRect(); 72 SkMatrix textureMatrix; 73 imgTransform.copyTo(textureMatrix); 74 75 // remove the y-flip applied to the matrix so that we can scale the srcRect. 76 // This flip is not needed as we specify the origin of the texture when we 77 // wrap it as an SkImage. 78 SkMatrix yFlip = SkMatrix::MakeScale(1, -1); 79 yFlip.postTranslate(0,1); 80 textureMatrix.preConcat(yFlip); 81 82 // copy the entire src if the rect is empty 83 if (skiaSrcRect.isEmpty()) { 84 skiaSrcRect = bufferRect; 85 } 86 87 // since the y-flip has been removed we can simply scale & translate 88 // the source rectangle 89 textureMatrix.mapRect(&skiaSrcRect); 90 91 if (skiaSrcRect.intersect(bufferRect)) { 92 SkPoint srcOrigin = SkPoint::Make(skiaSrcRect.fLeft, skiaSrcRect.fTop); 93 94 // if we need to scale the result we must render to an offscreen buffer 95 if (bitmap->width() != skiaSrcRect.width() 96 || bitmap->height() != skiaSrcRect.height()) { 97 sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget( 98 grContext.get(), SkBudgeted::kYes, bitmap->info()); 99 SkPaint paint; 100 paint.setBlendMode(SkBlendMode::kSrc); 101 scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, 102 SkRect::MakeWH(bitmap->width(), bitmap->height()), &paint); 103 image = scaledSurface->makeImageSnapshot(); 104 srcOrigin.set(0,0); 105 } 106 107 if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 108 srcOrigin.fX, srcOrigin.fY)) { 109 copyResult = CopyResult::Success; 110 } 111 } 112 } 113 114 // make sure that we have deleted the texture (in the SkImage) before we 115 // destroy the EGLImage that it was created from 116 image.reset(); 117 return copyResult; 118} 119 120} /* namespace skiapipeline */ 121} /* namespace uirenderer */ 122} /* namespace android */ 123