diff options
-rw-r--r-- | libs/hwui/Android.mk | 3 | ||||
-rw-r--r-- | libs/hwui/OpenGLReadback.cpp (renamed from libs/hwui/Readback.cpp) | 141 | ||||
-rw-r--r-- | libs/hwui/OpenGLReadback.h | 56 | ||||
-rw-r--r-- | libs/hwui/Readback.h | 17 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/LayerDrawable.cpp | 25 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/LayerDrawable.h | 1 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp | 16 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp | 121 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaOpenGLReadback.h | 35 | ||||
-rw-r--r-- | libs/hwui/renderthread/OpenGLPipeline.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderThread.cpp | 26 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderThread.h | 3 |
13 files changed, 359 insertions, 95 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 47220508f2bd..fdf4d52f357b 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -24,6 +24,7 @@ hwui_src_files := \ pipeline/skia/ReorderBarrierDrawables.cpp \ pipeline/skia/SkiaDisplayList.cpp \ pipeline/skia/SkiaOpenGLPipeline.cpp \ + pipeline/skia/SkiaOpenGLReadback.cpp \ pipeline/skia/SkiaPipeline.cpp \ pipeline/skia/SkiaProfileRenderer.cpp \ pipeline/skia/SkiaRecordingCanvas.cpp \ @@ -84,6 +85,7 @@ hwui_src_files := \ LayerUpdateQueue.cpp \ Matrix.cpp \ OpDumper.cpp \ + OpenGLReadback.cpp \ Patch.cpp \ PatchCache.cpp \ PathCache.cpp \ @@ -96,7 +98,6 @@ hwui_src_files := \ Properties.cpp \ PropertyValuesAnimatorSet.cpp \ PropertyValuesHolder.cpp \ - Readback.cpp \ RecordingCanvas.cpp \ RenderBufferCache.cpp \ RenderNode.cpp \ diff --git a/libs/hwui/Readback.cpp b/libs/hwui/OpenGLReadback.cpp index 1645218495eb..da6d994f436c 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/OpenGLReadback.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Readback.h" +#include "OpenGLReadback.h" #include "Caches.h" #include "Image.h" @@ -31,8 +31,69 @@ namespace android { namespace uirenderer { -static CopyResult copyTextureInto(Caches& caches, RenderState& renderState, - Texture& sourceTexture, Matrix4& texTransform, const Rect& srcRect, +CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, + SkBitmap* bitmap) { + ATRACE_CALL(); + mRenderThread.eglManager().initialize(); + + // Setup the source + sp<GraphicBuffer> sourceBuffer; + sp<Fence> sourceFence; + Matrix4 texTransform; + status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, + texTransform.data); + texTransform.invalidateType(); + if (err != NO_ERROR) { + ALOGW("Failed to get last queued buffer, error = %d", err); + return CopyResult::UnknownError; + } + if (!sourceBuffer.get()) { + ALOGW("Surface doesn't have any previously queued frames, nothing to readback from"); + return CopyResult::SourceEmpty; + } + if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) { + ALOGW("Surface is protected, unable to copy from it"); + return CopyResult::SourceInvalid; + } + err = sourceFence->wait(500 /* ms */); + if (err != NO_ERROR) { + ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt"); + return CopyResult::Timeout; + } + + // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via + // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES + // to be able to properly sample from the buffer. + + // Create the EGLImage object that maps the GraphicBuffer + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + EGLClientBuffer clientBuffer = (EGLClientBuffer) sourceBuffer->getNativeBuffer(); + EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; + + EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, + EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs); + + if (sourceImage == EGL_NO_IMAGE_KHR) { + ALOGW("eglCreateImageKHR failed (%#x)", eglGetError()); + return CopyResult::UnknownError; + } + + CopyResult copyResult = copyImageInto(sourceImage, texTransform, sourceBuffer->getWidth(), + sourceBuffer->getHeight(), srcRect, bitmap); + + // All we're flushing & finishing is the deletion of the texture since + // copyImageInto already did a major flush & finish as an implicit + // part of glReadPixels, so this shouldn't pose any major stalls. + glFinish(); + eglDestroyImageKHR(display, sourceImage); + return copyResult; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, + Texture& sourceTexture, const Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) { int destWidth = bitmap->width(); int destHeight = bitmap->height(); @@ -134,88 +195,40 @@ static CopyResult copyTextureInto(Caches& caches, RenderState& renderState, return CopyResult::Success; } -CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread, - Surface& surface, const Rect& srcRect, SkBitmap* bitmap) { - ATRACE_CALL(); - renderThread.eglManager().initialize(); +CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, + const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect, + SkBitmap* bitmap) { Caches& caches = Caches::getInstance(); - - // Setup the source - sp<GraphicBuffer> sourceBuffer; - sp<Fence> sourceFence; - Matrix4 texTransform; - status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, - texTransform.data); - texTransform.invalidateType(); - if (err != NO_ERROR) { - ALOGW("Failed to get last queued buffer, error = %d", err); - return CopyResult::UnknownError; - } - if (!sourceBuffer.get()) { - ALOGW("Surface doesn't have any previously queued frames, nothing to readback from"); - return CopyResult::SourceEmpty; - } - if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) { - ALOGW("Surface is protected, unable to copy from it"); - return CopyResult::SourceInvalid; - } - err = sourceFence->wait(500 /* ms */); - if (err != NO_ERROR) { - ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt"); - return CopyResult::Timeout; - } - - // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via - // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES - // to be able to properly sample from the buffer. - - // Create the EGLImage object that maps the GraphicBuffer - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - EGLClientBuffer clientBuffer = (EGLClientBuffer) sourceBuffer->getNativeBuffer(); - EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; - - EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, - EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs); - - if (sourceImage == EGL_NO_IMAGE_KHR) { - ALOGW("eglCreateImageKHR failed (%#x)", eglGetError()); - return CopyResult::UnknownError; - } GLuint sourceTexId; // Create a 2D texture to sample from the EGLImage glGenTextures(1, &sourceTexId); caches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId); - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, sourceImage); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage); GLenum status = GL_NO_ERROR; while ((status = glGetError()) != GL_NO_ERROR) { ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status); - eglDestroyImageKHR(display, sourceImage); return CopyResult::UnknownError; } Texture sourceTexture(caches); - sourceTexture.wrap(sourceTexId, sourceBuffer->getWidth(), - sourceBuffer->getHeight(), 0, 0 /* total lie */, GL_TEXTURE_EXTERNAL_OES); + sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */, + GL_TEXTURE_EXTERNAL_OES); - CopyResult copyResult = copyTextureInto(caches, renderThread.renderState(), - sourceTexture, texTransform, srcRect, bitmap); + CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), + sourceTexture, imgTransform, srcRect, bitmap); sourceTexture.deleteTexture(); - // All we're flushing & finishing is the deletion of the texture since - // copyTextureInto already did a major flush & finish as an implicit - // part of glReadPixels, so this shouldn't pose any major stalls. - glFinish(); - eglDestroyImageKHR(display, sourceImage); return copyResult; } -CopyResult Readback::copyTextureLayerInto(renderthread::RenderThread& renderThread, +bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, Layer& layer, SkBitmap* bitmap) { - ATRACE_CALL(); - return copyTextureInto(Caches::getInstance(), renderThread.renderState(), - layer.getTexture(), layer.getTexTransform(), Rect(), bitmap); + return CopyResult::Success == copyTextureInto(Caches::getInstance(), + renderThread.renderState(), layer.getTexture(), layer.getTexTransform(), + Rect(), bitmap); } + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/OpenGLReadback.h b/libs/hwui/OpenGLReadback.h new file mode 100644 index 000000000000..7ec2a96a9ac6 --- /dev/null +++ b/libs/hwui/OpenGLReadback.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Readback.h" + +namespace android { +namespace uirenderer { + +class Matrix4; +class Layer; + +class OpenGLReadback : public Readback { +public: + virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, + SkBitmap* bitmap) override; + +protected: + explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {} + virtual ~OpenGLReadback() {} + + virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, + int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) = 0; +}; + +class OpenGLReadbackImpl : public OpenGLReadback { +public: + OpenGLReadbackImpl(renderthread::RenderThread& thread) : OpenGLReadback(thread) {} + + /** + * Copies the layer's contents into the provided bitmap. + */ + static bool copyLayerInto(renderthread::RenderThread& renderThread, Layer& layer, + SkBitmap* bitmap); + +protected: + virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, + int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override; +}; + +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h index 55c943c0ebee..7fbc4bf48c4e 100644 --- a/libs/hwui/Readback.h +++ b/libs/hwui/Readback.h @@ -25,8 +25,6 @@ namespace android { namespace uirenderer { -class Layer; - // Keep in sync with PixelCopy.java codes enum class CopyResult { Success = 0, @@ -42,15 +40,14 @@ public: /** * Copies the surface's most recently queued buffer into the provided bitmap. */ - static CopyResult copySurfaceInto(renderthread::RenderThread& renderThread, - Surface& surface, const Rect& srcRect, SkBitmap* bitmap); + virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, + SkBitmap* bitmap) = 0; - /** - * Copies the TextureLayer's texture content (thus, the currently rendering buffer) into the - * provided bitmap. - */ - static CopyResult copyTextureLayerInto(renderthread::RenderThread& renderThread, - Layer& layer, SkBitmap* bitmap); +protected: + explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {} + virtual ~Readback() {} + + renderthread::RenderThread& mRenderThread; }; } // namespace uirenderer diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index 13a0ed852816..f2af4a891b12 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -23,36 +23,41 @@ namespace uirenderer { namespace skiapipeline { void LayerDrawable::onDraw(SkCanvas* canvas) { + DrawLayer(canvas->getGrContext(), canvas, mLayer.get()); +} + +bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) { // transform the matrix based on the layer int saveCount = -1; - if (!mLayer->getTransform().isIdentity()) { + if (!layer->getTransform().isIdentity()) { saveCount = canvas->save(); SkMatrix transform; - mLayer->getTransform().copyTo(transform); + layer->getTransform().copyTo(transform); canvas->concat(transform); } GrGLTextureInfo externalTexture; - externalTexture.fTarget = mLayer->getRenderTarget(); - externalTexture.fID = mLayer->getTextureId(); - GrContext* context = canvas->getGrContext(); + externalTexture.fTarget = layer->getRenderTarget(); + externalTexture.fID = layer->getTextureId(); GrBackendTextureDesc textureDescription; - textureDescription.fWidth = mLayer->getWidth(); - textureDescription.fHeight = mLayer->getHeight(); + textureDescription.fWidth = layer->getWidth(); + textureDescription.fHeight = layer->getHeight(); textureDescription.fConfig = kRGBA_8888_GrPixelConfig; textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin; textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture); sk_sp<SkImage> layerImage = SkImage::MakeFromTexture(context, textureDescription); if (layerImage) { SkPaint paint; - paint.setAlpha(mLayer->getAlpha()); - paint.setBlendMode(mLayer->getMode()); - paint.setColorFilter(sk_ref_sp(mLayer->getColorFilter())); + paint.setAlpha(layer->getAlpha()); + paint.setBlendMode(layer->getMode()); + paint.setColorFilter(sk_ref_sp(layer->getColorFilter())); canvas->drawImage(layerImage, 0, 0, &paint); } // restore the original matrix if (saveCount >= 0) { canvas->restoreToCount(saveCount); } + + return layerImage; } }; // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 91e274475b34..431989519a70 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -33,6 +33,7 @@ class LayerDrawable : public SkDrawable { explicit LayerDrawable(Layer* layer) : mLayer(layer) {} + static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer); protected: virtual SkRect onGetBounds() override { return SkRect::MakeWH(mLayer->getWidth(), mLayer->getHeight()); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index f046e4b93db1..7f3474a1bdf3 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -17,9 +17,9 @@ #include "SkiaOpenGLPipeline.h" #include "DeferredLayerUpdater.h" +#include "LayerDrawable.h" #include "renderthread/EglManager.h" #include "renderstate/RenderState.h" -#include "Readback.h" #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" #include "utils/TraceUtils.h" @@ -121,10 +121,16 @@ bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, return *requireSwap; } -bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { - layer->apply(); - return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap) - == CopyResult::Success; +bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) { + if (!mRenderThread.getGrContext()) { + return false; + } + + deferredLayer->apply(); + + SkCanvas canvas(*bitmap); + Layer* layer = deferredLayer->backingLayer(); + return LayerDrawable::DrawLayer(mRenderThread.getGrContext(), &canvas, layer); } DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp new file mode 100644 index 000000000000..a18d26471a29 --- /dev/null +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SkiaOpenGLReadback.h" + +#include "Matrix.h" +#include "Properties.h" +#include <SkCanvas.h> +#include <SkSurface.h> +#include <gl/GrGLInterface.h> +#include <gl/GrGLTypes.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +using namespace android::uirenderer::renderthread; + +namespace android { +namespace uirenderer { +namespace skiapipeline { + +CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, + int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) { + + GLuint sourceTexId; + glGenTextures(1, &sourceTexId); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage); + + sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext()); + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { + sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface()); + LOG_ALWAYS_FATAL_IF(!glInterface.get()); + grContext.reset(GrContext::Create(GrBackend::kOpenGL_GrBackend, + (GrBackendContext)glInterface.get())); + } else { + grContext->resetContext(); + } + + GrGLTextureInfo externalTexture; + externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES; + externalTexture.fID = sourceTexId; + + GrBackendTextureDesc textureDescription; + textureDescription.fWidth = imgWidth; + textureDescription.fHeight = imgHeight; + textureDescription.fConfig = kRGBA_8888_GrPixelConfig; + textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin; + textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture); + + CopyResult copyResult = CopyResult::UnknownError; + sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription)); + if (image) { + SkAutoLockPixels alp(*bitmap); + + // convert to Skia data structures + const SkRect bufferRect = SkRect::MakeIWH(imgWidth, imgHeight); + SkRect skiaSrcRect = srcRect.toSkRect(); + SkMatrix textureMatrix; + imgTransform.copyTo(textureMatrix); + + // remove the y-flip applied to the matrix so that we can scale the srcRect. + // This flip is not needed as we specify the origin of the texture when we + // wrap it as an SkImage. + SkMatrix yFlip = SkMatrix::MakeScale(1, -1); + yFlip.postTranslate(0,1); + textureMatrix.preConcat(yFlip); + + // copy the entire src if the rect is empty + if (skiaSrcRect.isEmpty()) { + skiaSrcRect = bufferRect; + } + + // since the y-flip has been removed we can simply scale & translate + // the source rectangle + textureMatrix.mapRect(&skiaSrcRect); + + if (skiaSrcRect.intersect(bufferRect)) { + SkPoint srcOrigin = SkPoint::Make(skiaSrcRect.fLeft, skiaSrcRect.fTop); + + // if we need to scale the result we must render to an offscreen buffer + if (bitmap->width() != skiaSrcRect.width() + || bitmap->height() != skiaSrcRect.height()) { + sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget( + grContext.get(), SkBudgeted::kYes, bitmap->info()); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); + scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, + SkRect::MakeWH(bitmap->width(), bitmap->height()), &paint); + image = scaledSurface->makeImageSnapshot(); + srcOrigin.set(0,0); + } + + if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), + srcOrigin.fX, srcOrigin.fY)) { + copyResult = CopyResult::Success; + } + } + } + + // make sure that we have deleted the texture (in the SkImage) before we + // destroy the EGLImage that it was created from + image.reset(); + return copyResult; +} + +} /* namespace skiapipeline */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h new file mode 100644 index 000000000000..d914409628d0 --- /dev/null +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "OpenGLReadback.h" + +namespace android { +namespace uirenderer { +namespace skiapipeline { + +class SkiaOpenGLReadback : public OpenGLReadback { +public: + SkiaOpenGLReadback(renderthread::RenderThread& thread) : OpenGLReadback(thread) {} +protected: + virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, + int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override; +}; + +} /* namespace skiapipeline */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp index afeeef86d22c..177a729cbf55 100644 --- a/libs/hwui/renderthread/OpenGLPipeline.cpp +++ b/libs/hwui/renderthread/OpenGLPipeline.cpp @@ -20,7 +20,7 @@ #include "EglManager.h" #include "ProfileRenderer.h" #include "renderstate/RenderState.h" -#include "Readback.h" +#include "OpenGLReadback.h" #include <android/native_window.h> #include <cutils/properties.h> @@ -117,9 +117,9 @@ bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& sc } bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { + ATRACE_CALL(); layer->apply(); - return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap) - == CopyResult::Success; + return OpenGLReadbackImpl::copyLayerInto(mRenderThread, *(layer->backingLayer()), bitmap); } DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() { diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 39e5931da361..2c4824279325 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -602,8 +602,8 @@ void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observer) { CREATE_BRIDGE4(copySurfaceInto, RenderThread* thread, Surface* surface, Rect srcRect, SkBitmap* bitmap) { - return (void*) Readback::copySurfaceInto(*args->thread, - *args->surface, args->srcRect, args->bitmap); + return (void*)args->thread->readback().copySurfaceInto(*args->surface, + args->srcRect, args->bitmap); } int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index f3789c8d8cbb..223958a3c319 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -17,8 +17,10 @@ #include "RenderThread.h" #include "../renderstate/RenderState.h" +#include "../pipeline/skia/SkiaOpenGLReadback.h" #include "CanvasContext.h" #include "EglManager.h" +#include "OpenGLReadback.h" #include "RenderProxy.h" #include "VulkanManager.h" @@ -196,6 +198,30 @@ void RenderThread::initThreadLocals() { mVkManager = new VulkanManager(*this); } +Readback& RenderThread::readback() { + + if (!mReadback) { + auto renderType = Properties::getRenderPipelineType(); + switch (renderType) { + case RenderPipelineType::OpenGL: + mReadback = new OpenGLReadbackImpl(*this); + break; + case RenderPipelineType::SkiaGL: + case RenderPipelineType::SkiaVulkan: + // It works to use the OpenGL pipeline for Vulkan but this is not + // ideal as it causes us to create an OpenGL context in addition + // to the Vulkan one. + mReadback = new skiapipeline::SkiaOpenGLReadback(*this); + break; + default: + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + break; + } + } + + return *mReadback; +} + int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) { if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { ALOGE("Display event receiver pipe was closed or an error occurred. " diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 12050dd9c772..d121bcf5b084 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -37,6 +37,7 @@ class DisplayEventReceiver; namespace uirenderer { +class Readback; class RenderState; class TestUtils; @@ -93,6 +94,7 @@ public: RenderState& renderState() const { return *mRenderState; } EglManager& eglManager() const { return *mEglManager; } JankTracker& jankTracker() { return *mJankTracker; } + Readback& readback(); const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; } @@ -151,6 +153,7 @@ private: EglManager* mEglManager; JankTracker* mJankTracker = nullptr; + Readback* mReadback = nullptr; sk_sp<GrContext> mGrContext; VulkanManager* mVkManager; |