diff options
26 files changed, 353 insertions, 495 deletions
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 8083a6a27da7..0a252716b69e 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -1198,6 +1198,10 @@ static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bit static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) { sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer)); + // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888 + // format and SRGB color space. + // To support any color space, we need to pass an additional ColorSpace argument to + // java Bitmap.createHardwareBitmap. sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer); if (!bitmap.get()) { ALOGW("failed to create hardware bitmap from graphic buffer"); diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 4a1774279d28..3c59bd1e3856 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -1024,6 +1024,9 @@ static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode( // Continue I guess? } sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer); + // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888 + // format and SRGB color space. + // To support any color space, we could extract it from BufferItem and pass it to Bitmap. return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_Premultiplied); } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 2baacbf541dc..e063e0bd9c3e 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -170,7 +170,6 @@ cc_defaults { "pipeline/skia/SkiaDisplayList.cpp", "pipeline/skia/SkiaMemoryTracer.cpp", "pipeline/skia/SkiaOpenGLPipeline.cpp", - "pipeline/skia/SkiaOpenGLReadback.cpp", "pipeline/skia/SkiaPipeline.cpp", "pipeline/skia/SkiaProfileRenderer.cpp", "pipeline/skia/SkiaRecordingCanvas.cpp", @@ -217,13 +216,13 @@ cc_defaults { "Layer.cpp", "LayerUpdateQueue.cpp", "Matrix.cpp", - "EglReadback.cpp", "PathParser.cpp", "ProfileData.cpp", "ProfileDataContainer.cpp", "Properties.cpp", "PropertyValuesAnimatorSet.cpp", "PropertyValuesHolder.cpp", + "Readback.cpp", "RecordingCanvas.cpp", "RenderNode.cpp", "RenderProperties.cpp", diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 00916559a9c2..837d5461d2a8 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -49,6 +49,7 @@ void DeferredLayerUpdater::destroyLayer() { } mLayer->postDecStrong(); + mLayer = nullptr; } diff --git a/libs/hwui/EglReadback.cpp b/libs/hwui/EglReadback.cpp deleted file mode 100644 index 65becf88b930..000000000000 --- a/libs/hwui/EglReadback.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 "EglReadback.h" - -#include "renderthread/EglManager.h" - -#include <gui/Surface.h> -#include <ui/Fence.h> -#include <ui/GraphicBuffer.h> - -namespace android { -namespace uirenderer { - -CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) { - ATRACE_CALL(); - // 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; - } - - return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap); -} - -CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform, - const Rect& srcRect, SkBitmap* bitmap) { - mRenderThread.requireGlContext(); - // 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)graphicBuffer->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; - } - - uint32_t width = graphicBuffer->getWidth(); - uint32_t height = graphicBuffer->getHeight(); - CopyResult copyResult = - copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap); - - eglDestroyImageKHR(display, sourceImage); - return copyResult; -} - -CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) { - Rect srcRect; - Matrix4 transform; - transform.loadScale(1, -1, 1); - transform.translate(0, -1); - return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap); -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/EglReadback.h b/libs/hwui/EglReadback.h deleted file mode 100644 index e723169ad795..000000000000 --- a/libs/hwui/EglReadback.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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" - -#include "Matrix.h" - -#include <EGL/egl.h> -#include <EGL/eglext.h> - -namespace android { -namespace uirenderer { - -class EglReadback : public Readback { -public: - virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, - SkBitmap* bitmap) override; - virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, - SkBitmap* bitmap) override; - -protected: - explicit EglReadback(renderthread::RenderThread& thread) : Readback(thread) {} - virtual ~EglReadback() {} - - virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, - int imgWidth, int imgHeight, const Rect& srcRect, - SkBitmap* bitmap) = 0; - -private: - CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform, - const Rect& srcRect, SkBitmap* bitmap); -}; - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index f59a2e6ee5c1..cc95051fc952 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -26,8 +26,7 @@ namespace uirenderer { Layer::Layer(RenderState& renderState, sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode) - : GpuMemoryTracker(GpuObjectType::Layer) - , mRenderState(renderState) + : mRenderState(renderState) , mColorFilter(colorFilter) , alpha(alpha) , mode(mode) { diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index c4e4c1c96ba6..6f07a43ceb58 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -16,7 +16,6 @@ #pragma once -#include <GpuMemoryTracker.h> #include <utils/RefBase.h> #include <SkBlendMode.h> @@ -39,21 +38,21 @@ class RenderState; /** * A layer has dimensions and is backed by a backend specific texture or framebuffer. */ -class Layer : public VirtualLightRefBase, GpuMemoryTracker { +class Layer : public VirtualLightRefBase { public: Layer(RenderState& renderState, sk_sp<SkColorFilter>, int alpha, SkBlendMode mode); ~Layer(); - virtual uint32_t getWidth() const { return mWidth; } + uint32_t getWidth() const { return mWidth; } - virtual uint32_t getHeight() const { return mHeight; } + uint32_t getHeight() const { return mHeight; } - virtual void setSize(uint32_t width, uint32_t height) { mWidth = width; mHeight = height; } + void setSize(uint32_t width, uint32_t height) { mWidth = width; mHeight = height; } - virtual void setBlend(bool blend) { mBlend = blend; } + void setBlend(bool blend) { mBlend = blend; } - virtual bool isBlend() const { return mBlend; } + bool isBlend() const { return mBlend; } inline void setForceFilter(bool forceFilter) { this->forceFilter = forceFilter; } diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp new file mode 100644 index 000000000000..80f2b5714659 --- /dev/null +++ b/libs/hwui/Readback.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2018 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 "Readback.h" + +#include "pipeline/skia/LayerDrawable.h" +#include "renderthread/EglManager.h" +#include "renderthread/VulkanManager.h" + +#include <SkToSRGBColorFilter.h> +#include <gui/Surface.h> +#include <ui/Fence.h> +#include <ui/GraphicBuffer.h> +#include "DeferredLayerUpdater.h" +#include "Properties.h" +#include "hwui/Bitmap.h" +#include "utils/Color.h" +#include "utils/MathUtils.h" + +using namespace android::uirenderer::renderthread; + +namespace android { +namespace uirenderer { + +CopyResult Readback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) { + ATRACE_CALL(); + // 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; + } + if (!sourceBuffer.get()) { + return CopyResult::UnknownError; + } + + sk_sp<SkColorSpace> colorSpace = + DataSpaceToColorSpace(static_cast<android_dataspace>(surface.getBuffersDataSpace())); + sk_sp<SkColorFilter> colorSpaceFilter; + if (colorSpace && !colorSpace->isSRGB()) { + colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); + } + sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer( + reinterpret_cast<AHardwareBuffer*>(sourceBuffer.get()), kPremul_SkAlphaType); + return copyImageInto(image, colorSpaceFilter, texTransform, srcRect, bitmap); +} + +CopyResult Readback::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { + LOG_ALWAYS_FATAL_IF(!hwBitmap->isHardware()); + + Rect srcRect; + Matrix4 transform; + transform.loadScale(1, -1, 1); + transform.translate(0, -1); + + // TODO: Try to take and reuse the image inside HW bitmap with "hwBitmap->makeImage". + // TODO: When this was attempted, it resulted in instability. + sk_sp<SkColorFilter> colorSpaceFilter; + sk_sp<SkColorSpace> colorSpace = hwBitmap->info().refColorSpace(); + if (colorSpace && !colorSpace->isSRGB()) { + colorSpaceFilter = SkToSRGBColorFilter::Make(colorSpace); + } + sk_sp<SkImage> image = SkImage::MakeFromAHardwareBuffer( + reinterpret_cast<AHardwareBuffer*>(hwBitmap->graphicBuffer()), kPremul_SkAlphaType); + + // HW Bitmap currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888 format + // and SRGB color space. ImageDecoder can create a new HW Bitmap with non-SRGB color space: for + // example see android.graphics.cts.BitmapColorSpaceTest#testEncodeP3hardware test. + return copyImageInto(image, colorSpaceFilter, transform, srcRect, bitmap); +} + +CopyResult Readback::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) { + if (!mRenderThread.getGrContext()) { + return CopyResult::UnknownError; + } + + // acquire most recent buffer for drawing + deferredLayer->updateTexImage(); + deferredLayer->apply(); + const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height()); + CopyResult copyResult = CopyResult::UnknownError; + Layer* layer = deferredLayer->backingLayer(); + if (layer) { + if (copyLayerInto(layer, nullptr, &dstRect, bitmap)) { + copyResult = CopyResult::Success; + } + } + return copyResult; +} + +CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, + sk_sp<SkColorFilter>& colorSpaceFilter, Matrix4& texTransform, + const Rect& srcRect, SkBitmap* bitmap) { + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { + mRenderThread.requireGlContext(); + } else { + mRenderThread.vulkanManager().initialize(); + } + if (!image.get()) { + return CopyResult::UnknownError; + } + int imgWidth = image->width(); + int imgHeight = image->height(); + sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext()); + + if (bitmap->colorType() == kRGBA_F16_SkColorType && + !grContext->colorTypeSupportedAsSurface(bitmap->colorType())) { + ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); + return CopyResult::DestinationInvalid; + } + + CopyResult copyResult = CopyResult::UnknownError; + + int displayedWidth = imgWidth, displayedHeight = imgHeight; + // If this is a 90 or 270 degree rotation we need to swap width/height to get the device + // size. + if (texTransform[Matrix4::kSkewX] >= 0.5f || texTransform[Matrix4::kSkewX] <= -0.5f) { + std::swap(displayedWidth, displayedHeight); + } + SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height()); + SkRect skiaSrcRect = srcRect.toSkRect(); + if (skiaSrcRect.isEmpty()) { + skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight); + } + bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight)); + if (!srcNotEmpty) { + return copyResult; + } + + // See Readback::copyLayerInto for an overview of color space conversion. + // HW Bitmap are allowed to be in a non-SRGB color space (for example coming from ImageDecoder). + // For Surface and HW Bitmap readback flows we pass colorSpaceFilter, which does the conversion. + // TextureView readback is using Layer::setDataSpace, which creates a SkColorFilter internally. + Layer layer(mRenderThread.renderState(), colorSpaceFilter, 255, SkBlendMode::kSrc); + bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) && + MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height()); + layer.setForceFilter(!disableFilter); + layer.setSize(displayedWidth, displayedHeight); + texTransform.copyTo(layer.getTexTransform()); + layer.setImage(image); + if (copyLayerInto(&layer, &skiaSrcRect, &skiaDestRect, bitmap)) { + copyResult = CopyResult::Success; + } + + return copyResult; +} + +bool Readback::copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect, + SkBitmap* bitmap) { + /* + * In the past only TextureView readback was setting the temporary surface color space to null. + * Now all 3 readback flows are drawing into a SkSurface with null color space. + * At readback there are 3 options to convert the source image color space to the destination + * color space requested in "bitmap->info().colorSpace()": + * 1. Set color space for temporary surface render target to null (disables color management), + * colorspace tag from source SkImage is ignored by Skia, + * convert SkImage to SRGB at draw time with SkColorFilter/SkToSRGBColorFilter, + * do a readback from temporary SkSurface to a temporary SRGB SkBitmap "bitmap2", + * read back from SRGB "bitmap2" into non-SRGB "bitmap" which will do a CPU color conversion. + * + * 2. Set color space for temporary surface render target to SRGB (not nullptr), + * colorspace tag on the source SkImage is used by Skia to enable conversion, + * convert SkImage to SRGB at draw time with drawImage (no filters), + * do a readback from temporary SkSurface, which will do a color conversion from SRGB to + * bitmap->info().colorSpace() on the CPU. + * + * 3. Set color space for temporary surface render target to bitmap->info().colorSpace(), + * colorspace tag on the source SkImage is used by Skia to enable conversion, + * convert SkImage to bitmap->info().colorSpace() at draw time with drawImage (no filters), + * do a readback from SkSurface, which will not do any color conversion, because + * surface was created with the same color space as the "bitmap". + * + * Option 1 is used for all readback flows. + * Options 2 and 3 are new, because skia added support for non-SRGB render targets without + * linear blending. + * TODO: evaluate if options 2 or 3 for color space conversion are better. + */ + + // drop the colorSpace from the temporary surface. + SkImageInfo surfaceInfo = bitmap->info().makeColorSpace(nullptr); + + /* This intermediate surface is present to work around a bug in SwiftShader that + * prevents us from reading the contents of the layer's texture directly. The + * workaround involves first rendering that texture into an intermediate buffer and + * then reading from the intermediate buffer into the bitmap. + * Another reason to render in an offscreen buffer is to scale and to avoid an issue b/62262733 + * with reading incorrect data from EGLImage backed SkImage (likely a driver bug). + */ + sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), + SkBudgeted::kYes, surfaceInfo); + + if (!tmpSurface.get()) { + surfaceInfo = surfaceInfo.makeColorType(SkColorType::kN32_SkColorType); + tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes, + surfaceInfo); + if (!tmpSurface.get()) { + ALOGW("Unable to readback GPU contents into the provided bitmap"); + return false; + } + } + + if (skiapipeline::LayerDrawable::DrawLayer(mRenderThread.getGrContext(), + tmpSurface->getCanvas(), layer, srcRect, dstRect, + false)) { + // If bitmap->info().colorSpace() is non-SRGB, convert the data from SRGB to non-SRGB on + // CPU. We can't just pass bitmap->info() to SkSurface::readPixels, because "tmpSurface" has + // disabled color conversion. + SkColorSpace* destColorSpace = bitmap->info().colorSpace(); + SkBitmap tempSRGBBitmap; + SkBitmap tmpN32Bitmap; + SkBitmap* bitmapInSRGB; + if (destColorSpace && !destColorSpace->isSRGB()) { + tempSRGBBitmap.allocPixels(bitmap->info().makeColorSpace(SkColorSpace::MakeSRGB())); + bitmapInSRGB = &tempSRGBBitmap; // Need to convert latter from SRGB to non-SRGB. + } else { + bitmapInSRGB = bitmap; // No need for color conversion - write directly into output. + } + bool success = false; + + // TODO: does any of the readbacks below clamp F16 exSRGB? + // Readback into a SRGB SkBitmap. + if (tmpSurface->readPixels(bitmapInSRGB->info(), bitmapInSRGB->getPixels(), + bitmapInSRGB->rowBytes(), 0, 0)) { + success = true; + } else { + // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into + // 8888 and then convert that into the destination format before giving up. + SkImageInfo bitmapInfo = + SkImageInfo::MakeN32(bitmap->width(), bitmap->height(), bitmap->alphaType(), + SkColorSpace::MakeSRGB()); + if (tmpN32Bitmap.tryAllocPixels(bitmapInfo) && + tmpSurface->readPixels(bitmapInfo, tmpN32Bitmap.getPixels(), + tmpN32Bitmap.rowBytes(), 0, 0)) { + success = true; + bitmapInSRGB = &tmpN32Bitmap; + } + } + + if (success) { + if (bitmapInSRGB != bitmap) { + // Convert from SRGB to non-SRGB color space if needed. Convert from N32 to + // destination bitmap color format if needed. + if (!bitmapInSRGB->readPixels(bitmap->info(), bitmap->getPixels(), + bitmap->rowBytes(), 0, 0)) { + return false; + } + } + bitmap->notifyPixelsChanged(); + return true; + } + } + + return false; +} + +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h index ad3a8b690617..d9e10cedc0e8 100644 --- a/libs/hwui/Readback.h +++ b/libs/hwui/Readback.h @@ -16,16 +16,21 @@ #pragma once +#include "Matrix.h" #include "Rect.h" #include "renderthread/RenderThread.h" #include <SkBitmap.h> namespace android { +class Bitmap; class GraphicBuffer; class Surface; namespace uirenderer { +class DeferredLayerUpdater; +class Layer; + // Keep in sync with PixelCopy.java codes enum class CopyResult { Success = 0, @@ -38,15 +43,22 @@ enum class CopyResult { class Readback { public: + explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {} /** * Copies the surface's most recently queued buffer into the provided bitmap. */ - virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) = 0; - virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) = 0; + CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap); -protected: - explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {} - virtual ~Readback() {} + CopyResult copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap); + + CopyResult copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); + +private: + CopyResult copyImageInto(const sk_sp<SkImage>& image, sk_sp<SkColorFilter>& colorSpaceFilter, + Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap); + + bool copyLayerInto(Layer* layer, const SkRect* srcRect, const SkRect* dstRect, + SkBitmap* bitmap); renderthread::RenderThread& mRenderThread; }; diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 3939696692d2..440620a6a417 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -290,7 +290,7 @@ void Bitmap::getSkBitmap(SkBitmap* outBitmap) { if (isHardware()) { outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(), info().colorType(), info().alphaType(), nullptr)); - uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap); + uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap); if (mInfo.colorSpace()) { sk_sp<SkPixelRef> pixelRef = sk_ref_sp(outBitmap->pixelRef()); outBitmap->setInfo(mInfo); diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index b6cd4b08e5fe..3ca0f8139c02 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -28,12 +28,13 @@ namespace skiapipeline { void LayerDrawable::onDraw(SkCanvas* canvas) { Layer* layer = mLayerUpdater->backingLayer(); if (layer) { - DrawLayer(canvas->getGrContext(), canvas, layer); + DrawLayer(canvas->getGrContext(), canvas, layer, nullptr, nullptr, true); } } bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, - const SkRect* dstRect) { + const SkRect* srcRect, const SkRect* dstRect, + bool useLayerTransform) { if (context == nullptr) { SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface")); return false; @@ -60,12 +61,10 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer } SkMatrix matrix; - if (dstRect) { - // Destination rectangle is set only when we are trying to read back the content - // of the layer. In this case we don't want to apply layer transform. - matrix = textureMatrix; - } else { + if (useLayerTransform) { matrix = SkMatrix::Concat(layerTransform, textureMatrix); + } else { + matrix = textureMatrix; } SkPaint paint; @@ -81,16 +80,26 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer canvas->save(); canvas->concat(matrix); } - if (dstRect) { + if (dstRect || srcRect) { SkMatrix matrixInv; if (!matrix.invert(&matrixInv)) { matrixInv = matrix; } - SkRect srcRect = SkRect::MakeIWH(layerWidth, layerHeight); - matrixInv.mapRect(&srcRect); - SkRect skiaDestRect = *dstRect; + SkRect skiaSrcRect; + if (srcRect) { + skiaSrcRect = *srcRect; + } else { + skiaSrcRect = SkRect::MakeIWH(layerWidth, layerHeight); + } + matrixInv.mapRect(&skiaSrcRect); + SkRect skiaDestRect; + if (dstRect) { + skiaDestRect = *dstRect; + } else { + skiaDestRect = SkRect::MakeIWH(layerWidth, layerHeight); + } matrixInv.mapRect(&skiaDestRect); - canvas->drawImageRect(layerImage.get(), srcRect, skiaDestRect, &paint, + canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, &paint, SkCanvas::kFast_SrcRectConstraint); } else { canvas->drawImage(layerImage.get(), 0, 0, &paint); diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 18d118405a39..5c125908ffb2 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -33,7 +33,7 @@ public: explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {} static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, - const SkRect* dstRect = nullptr); + const SkRect* srcRect, const SkRect* dstRect, bool useLayerTransform); protected: virtual SkRect onGetBounds() override { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 2ae37233098e..d58b59e83380 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -127,65 +127,6 @@ bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect return *requireSwap; } -bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) { - if (!mRenderThread.getGrContext()) { - return false; - } - - // acquire most recent buffer for drawing - deferredLayer->updateTexImage(); - deferredLayer->apply(); - - // drop the colorSpace as we only support readback into sRGB or extended sRGB - SkImageInfo surfaceInfo = bitmap->info().makeColorSpace(nullptr); - - /* This intermediate surface is present to work around a bug in SwiftShader that - * prevents us from reading the contents of the layer's texture directly. The - * workaround involves first rendering that texture into an intermediate buffer and - * then reading from the intermediate buffer into the bitmap. - */ - sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), - SkBudgeted::kYes, surfaceInfo); - - if (!tmpSurface.get()) { - surfaceInfo = surfaceInfo.makeColorType(SkColorType::kN32_SkColorType); - tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes, - surfaceInfo); - if (!tmpSurface.get()) { - ALOGW("Unable to readback GPU contents into the provided bitmap"); - return false; - } - } - - Layer* layer = deferredLayer->backingLayer(); - const SkRect dstRect = SkRect::MakeIWH(bitmap->width(), bitmap->height()); - if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer, - &dstRect)) { - sk_sp<SkImage> tmpImage = tmpSurface->makeImageSnapshot(); - if (tmpImage->readPixels(surfaceInfo, bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { - bitmap->notifyPixelsChanged(); - return true; - } - - // if we fail to readback from the GPU directly (e.g. 565) then we attempt to read into 8888 - // and then draw that into the destination format before giving up. - SkBitmap tmpBitmap; - SkImageInfo bitmapInfo = - SkImageInfo::MakeN32(bitmap->width(), bitmap->height(), bitmap->alphaType()); - if (tmpBitmap.tryAllocPixels(bitmapInfo) && - tmpImage->readPixels(bitmapInfo, tmpBitmap.getPixels(), tmpBitmap.rowBytes(), 0, 0)) { - SkCanvas canvas(*bitmap); - SkPaint paint; - paint.setBlendMode(SkBlendMode::kSrc); - canvas.drawBitmap(tmpBitmap, 0, 0, &paint); - bitmap->notifyPixelsChanged(); - return true; - } - } - - return false; -} - DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() { mRenderThread.requireGlContext(); return new DeferredLayerUpdater(mRenderThread.renderState()); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index 2e2e1522b717..808685ad4460 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -40,7 +40,6 @@ public: FrameInfoVisualizer* profiler) override; bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) override; - bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override; DeferredLayerUpdater* createTextureLayer() override; bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior, renderthread::ColorMode colorMode) override; diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp deleted file mode 100644 index f2f5056bb195..000000000000 --- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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 <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <GrBackendSurface.h> -#include <SkCanvas.h> -#include <SkSurface.h> -#include <gl/GrGLInterface.h> -#include <gl/GrGLTypes.h> -#include "DeviceInfo.h" -#include "Matrix.h" -#include "Properties.h" -#include "utils/MathUtils.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 = GrContext::MakeGL(std::move(glInterface)); - } else { - grContext->resetContext(); - } - - if (bitmap->colorType() == kRGBA_F16_SkColorType && - !grContext->colorTypeSupportedAsSurface(bitmap->colorType())) { - ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); - return CopyResult::DestinationInvalid; - } - - GrGLTextureInfo externalTexture; - externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES; - externalTexture.fID = sourceTexId; - switch (bitmap->colorType()) { - case kRGBA_F16_SkColorType: - externalTexture.fFormat = GL_RGBA16F; - break; - case kN32_SkColorType: - default: - externalTexture.fFormat = GL_RGBA8; - break; - } - - GrBackendTexture backendTexture(imgWidth, imgHeight, GrMipMapped::kNo, externalTexture); - - CopyResult copyResult = CopyResult::UnknownError; - sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture, - kTopLeft_GrSurfaceOrigin, - bitmap->colorType())); - if (image) { - int displayedWidth = imgWidth, displayedHeight = imgHeight; - // If this is a 90 or 270 degree rotation we need to swap width/height to get the device - // size. - if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) { - std::swap(displayedWidth, displayedHeight); - } - SkRect skiaDestRect = SkRect::MakeWH(bitmap->width(), bitmap->height()); - SkRect skiaSrcRect = srcRect.toSkRect(); - if (skiaSrcRect.isEmpty()) { - skiaSrcRect = SkRect::MakeIWH(displayedWidth, displayedHeight); - } - bool srcNotEmpty = skiaSrcRect.intersect(SkRect::MakeIWH(displayedWidth, displayedHeight)); - - if (srcNotEmpty) { - SkMatrix textureMatrixInv; - imgTransform.copyTo(textureMatrixInv); - // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed - // use bottom left origin and remove flipV and invert transformations. - SkMatrix flipV; - flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1); - textureMatrixInv.preConcat(flipV); - textureMatrixInv.preScale(1.0f / displayedWidth, 1.0f / displayedHeight); - textureMatrixInv.postScale(imgWidth, imgHeight); - SkMatrix textureMatrix; - if (!textureMatrixInv.invert(&textureMatrix)) { - textureMatrix = textureMatrixInv; - } - - textureMatrixInv.mapRect(&skiaSrcRect); - textureMatrixInv.mapRect(&skiaDestRect); - - // we render in an offscreen buffer to scale and to avoid an issue b/62262733 - // with reading incorrect data from EGLImage backed SkImage (likely a driver bug) - sk_sp<SkSurface> scaledSurface = - SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kYes, bitmap->info()); - SkPaint paint; - paint.setBlendMode(SkBlendMode::kSrc); - // Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage - // is codified by tests using golden images like DecodeAccuracyTest. - bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) - && MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height()); - if (!disableFilter) { - paint.setFilterQuality(kLow_SkFilterQuality); - } - scaledSurface->getCanvas()->concat(textureMatrix); - scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint, - SkCanvas::kFast_SrcRectConstraint); - - image = scaledSurface->makeImageSnapshot(); - - if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { - bitmap->notifyPixelsChanged(); - 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(); - glFinish(); - - return copyResult; -} - -} /* namespace skiapipeline */ -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h deleted file mode 100644 index 1ce4773e7d67..000000000000 --- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 "EglReadback.h" - -namespace android { -namespace uirenderer { -namespace skiapipeline { - -class SkiaOpenGLReadback : public EglReadback { -public: - SkiaOpenGLReadback(renderthread::RenderThread& thread) : EglReadback(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/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 5f2eee4523fc..611a34c069d4 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -108,11 +108,6 @@ bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect return *requireSwap; } -bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { - // TODO: implement copyLayerInto for vulkan. - return false; -} - DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() { mVkManager.initialize(); diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 7806b42e03dc..900b054e35bd 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -38,7 +38,6 @@ public: FrameInfoVisualizer* profiler) override; bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) override; - bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override; DeferredLayerUpdater* createTextureLayer() override; bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior, renderthread::ColorMode colorMode) override; diff --git a/libs/hwui/pipeline/skia/SkiaVulkanReadback.h b/libs/hwui/pipeline/skia/SkiaVulkanReadback.h deleted file mode 100644 index 65b89d617f7b..000000000000 --- a/libs/hwui/pipeline/skia/SkiaVulkanReadback.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2018 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 { -namespace skiapipeline { - -class SkiaVulkanReadback : public Readback { -public: - SkiaVulkanReadback(renderthread::RenderThread& thread) : Readback(thread) {} - - virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, - SkBitmap* bitmap) override { - //TODO: implement Vulkan readback. - return CopyResult::UnknownError; - } - - virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, - SkBitmap* bitmap) override { - //TODO: implement Vulkan readback. - return CopyResult::UnknownError; - } -}; - -} /* namespace skiapipeline */ -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 8b07d1dadeb6..727cef3035f5 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -562,10 +562,6 @@ void CanvasContext::buildLayer(RenderNode* node) { mPrefetchedLayers.insert(node); } -bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { - return mRenderPipeline->copyLayerInto(layer, bitmap); -} - void CanvasContext::destroyHardwareResources() { stopDrawing(); if (mRenderPipeline->isContextReady()) { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 8ca54af13baa..02ee72f05f04 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -135,7 +135,6 @@ public: void prepareAndDraw(RenderNode* node); void buildLayer(RenderNode* node); - bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); void markLayerInUse(RenderNode* node); void destroyHardwareResources(); diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index b94a7588a507..b7b7853e6ed7 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -60,7 +60,6 @@ public: FrameInfoVisualizer* profiler) = 0; virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) = 0; - virtual bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) = 0; virtual DeferredLayerUpdater* createTextureLayer() = 0; virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0; virtual void onStop() = 0; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index e3807e634890..7a5348ac85d9 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -160,8 +160,10 @@ void RenderProxy::buildLayer(RenderNode* node) { } bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) { - return mRenderThread.queue().runSync( - [&]() -> bool { return mContext->copyLayerInto(layer, &bitmap); }); + auto& thread = RenderThread::getInstance(); + return thread.queue().runSync( + [&]() -> bool { return thread.readback().copyLayerInto(layer, &bitmap) + == CopyResult::Success; }); } void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) { @@ -331,14 +333,14 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) { } } -int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) { +int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { RenderThread& thread = RenderThread::getInstance(); if (gettid() == thread.getTid()) { // TODO: fix everything that hits this. We should never be triggering a readback ourselves. - return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap); + return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap); } else { return thread.queue().runSync([&]() -> int { - return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap); + return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap); }); } } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index c2964a4e3515..969ad00d7443 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -125,7 +125,7 @@ public: int bottom, SkBitmap* bitmap); ANDROID_API static void prepareToDraw(Bitmap& bitmap); - static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap); + static int copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap); static void onBitmapDestroyed(uint32_t pixelRefId); diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 2322fbf21f27..7258a0aa4f02 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -19,13 +19,12 @@ #include "CanvasContext.h" #include "DeviceInfo.h" #include "EglManager.h" +#include "Readback.h" #include "RenderProxy.h" #include "VulkanManager.h" #include "hwui/Bitmap.h" #include "pipeline/skia/SkiaOpenGLPipeline.h" -#include "pipeline/skia/SkiaOpenGLReadback.h" #include "pipeline/skia/SkiaVulkanPipeline.h" -#include "pipeline/skia/SkiaVulkanReadback.h" #include "renderstate/RenderState.h" #include "utils/FatVector.h" #include "utils/TimeUtils.h" @@ -235,18 +234,7 @@ void RenderThread::dumpGraphicsMemory(int fd) { Readback& RenderThread::readback() { if (!mReadback) { - auto renderType = Properties::getRenderPipelineType(); - switch (renderType) { - case RenderPipelineType::SkiaGL: - mReadback = new skiapipeline::SkiaOpenGLReadback(*this); - break; - case RenderPipelineType::SkiaVulkan: - mReadback = new skiapipeline::SkiaVulkanReadback(*this); - break; - default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); - break; - } + mReadback = new Readback(*this); } return *mReadback; |