Loading libs/hwui/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -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 \ Loading Loading @@ -84,6 +85,7 @@ hwui_src_files := \ LayerUpdateQueue.cpp \ Matrix.cpp \ OpDumper.cpp \ OpenGLReadback.cpp \ Patch.cpp \ PatchCache.cpp \ PathCache.cpp \ Loading @@ -96,7 +98,6 @@ hwui_src_files := \ Properties.cpp \ PropertyValuesAnimatorSet.cpp \ PropertyValuesHolder.cpp \ Readback.cpp \ RecordingCanvas.cpp \ RenderBufferCache.cpp \ RenderNode.cpp \ Loading libs/hwui/Readback.cpp→libs/hwui/OpenGLReadback.cpp +77 −64 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. */ #include "Readback.h" #include "OpenGLReadback.h" #include "Caches.h" #include "Image.h" Loading @@ -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(); Loading Loading @@ -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 libs/hwui/OpenGLReadback.h 0 → 100644 +56 −0 Original line number Diff line number Diff line /* * 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 libs/hwui/Readback.h +7 −10 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ namespace android { namespace uirenderer { class Layer; // Keep in sync with PixelCopy.java codes enum class CopyResult { Success = 0, Loading @@ -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 Loading libs/hwui/pipeline/skia/LayerDrawable.cpp +15 −10 Original line number Diff line number Diff line Loading @@ -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 Loading Loading
libs/hwui/Android.mk +2 −1 Original line number Diff line number Diff line Loading @@ -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 \ Loading Loading @@ -84,6 +85,7 @@ hwui_src_files := \ LayerUpdateQueue.cpp \ Matrix.cpp \ OpDumper.cpp \ OpenGLReadback.cpp \ Patch.cpp \ PatchCache.cpp \ PathCache.cpp \ Loading @@ -96,7 +98,6 @@ hwui_src_files := \ Properties.cpp \ PropertyValuesAnimatorSet.cpp \ PropertyValuesHolder.cpp \ Readback.cpp \ RecordingCanvas.cpp \ RenderBufferCache.cpp \ RenderNode.cpp \ Loading
libs/hwui/Readback.cpp→libs/hwui/OpenGLReadback.cpp +77 −64 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. */ #include "Readback.h" #include "OpenGLReadback.h" #include "Caches.h" #include "Image.h" Loading @@ -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(); Loading Loading @@ -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
libs/hwui/OpenGLReadback.h 0 → 100644 +56 −0 Original line number Diff line number Diff line /* * 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
libs/hwui/Readback.h +7 −10 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ namespace android { namespace uirenderer { class Layer; // Keep in sync with PixelCopy.java codes enum class CopyResult { Success = 0, Loading @@ -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 Loading
libs/hwui/pipeline/skia/LayerDrawable.cpp +15 −10 Original line number Diff line number Diff line Loading @@ -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 Loading