Support Surface and Layer Readback in the SkiaPipelines.
Test: CTS TextureViewTests and UIRendering
Change-Id: I2969c8f5a975bfd9aebcbb585c64d1fcbb2487c2
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 4722050..fdf4d52 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -24,6 +24,7 @@
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 @@
LayerUpdateQueue.cpp \
Matrix.cpp \
OpDumper.cpp \
+ OpenGLReadback.cpp \
Patch.cpp \
PatchCache.cpp \
PathCache.cpp \
@@ -96,7 +98,6 @@
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
similarity index 82%
rename from libs/hwui/Readback.cpp
rename to libs/hwui/OpenGLReadback.cpp
index 1645218..da6d994 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 @@
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 0000000..7ec2a96
--- /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 55c943c..7fbc4bf 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 @@
/**
* 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 13a0ed8..f2af4a8 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -23,36 +23,41 @@
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 91e2744..4319895 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -33,6 +33,7 @@
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 f046e4b..7f3474a 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 @@
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 0000000..a18d264
--- /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 0000000..d914409
--- /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 afeeef8..177a729 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::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 39e5931..2c48242 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -602,8 +602,8 @@
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 f3789c8..223958a 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 @@
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 12050dd..d121bcf 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -37,6 +37,7 @@
namespace uirenderer {
+class Readback;
class RenderState;
class TestUtils;
@@ -93,6 +94,7 @@
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 @@
EglManager* mEglManager;
JankTracker* mJankTracker = nullptr;
+ Readback* mReadback = nullptr;
sk_sp<GrContext> mGrContext;
VulkanManager* mVkManager;