Loading libs/hwui/Android.bp +1 −2 Original line number Diff line number Diff line Loading @@ -186,7 +186,6 @@ cc_defaults { "renderstate/TextureState.cpp", "renderthread/CacheManager.cpp", "renderthread/CanvasContext.cpp", "renderthread/OpenGLPipeline.cpp", "renderthread/DrawFrameTask.cpp", "renderthread/EglManager.cpp", "renderthread/VulkanManager.cpp", Loading Loading @@ -237,7 +236,7 @@ cc_defaults { "LayerUpdateQueue.cpp", "Matrix.cpp", "OpDumper.cpp", "OpenGLReadback.cpp", "EglReadback.cpp", "Patch.cpp", "PatchCache.cpp", "PathCache.cpp", Loading libs/hwui/OpenGLReadback.cpp→libs/hwui/EglReadback.cpp +97 −0 Original line number Diff line number Diff line Loading @@ -14,17 +14,10 @@ * limitations under the License. */ #include "OpenGLReadback.h" #include "EglReadback.h" #include "Caches.h" #include "GlLayer.h" #include "GlopBuilder.h" #include "Image.h" #include "renderstate/RenderState.h" #include "renderthread/EglManager.h" #include "utils/GLUtils.h" #include <GLES2/gl2.h> #include <gui/Surface.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> Loading @@ -32,7 +25,7 @@ namespace android { namespace uirenderer { CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) { ATRACE_CALL(); // Setup the source Loading Loading @@ -62,7 +55,7 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap); } CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) { mRenderThread.eglManager().initialize(); Loading @@ -88,15 +81,11 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, CopyResult copyResult = copyImageInto(sourceImage, texTransform, width, height, 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; } CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) { CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) { Rect srcRect; Matrix4 transform; transform.loadScale(1, -1, 1); Loading @@ -104,184 +93,5 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, S return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap); } static float sFlipVInit[16] = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, }; static const Matrix4 sFlipV(sFlipVInit); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// 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(); if (destWidth > caches.maxTextureSize || destHeight > caches.maxTextureSize) { ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d", destWidth, destHeight, caches.maxTextureSize); return CopyResult::DestinationInvalid; } if (bitmap->colorType() == kRGBA_F16_SkColorType && !caches.extensions().hasRenderableFloatTextures()) { ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); return CopyResult::DestinationInvalid; } GLuint fbo = renderState.createFramebuffer(); if (!fbo) { ALOGW("Could not obtain an FBO"); return CopyResult::UnknownError; } GLuint texture; GLenum format; GLenum internalFormat; GLenum type; switch (bitmap->colorType()) { case kAlpha_8_SkColorType: format = GL_ALPHA; internalFormat = GL_ALPHA; type = GL_UNSIGNED_BYTE; break; case kRGB_565_SkColorType: format = GL_RGB; internalFormat = GL_RGB; type = GL_UNSIGNED_SHORT_5_6_5; break; case kARGB_4444_SkColorType: format = GL_RGBA; internalFormat = GL_RGBA; type = GL_UNSIGNED_SHORT_4_4_4_4; break; case kRGBA_F16_SkColorType: format = GL_RGBA; internalFormat = GL_RGBA16F; type = GL_HALF_FLOAT; break; case kN32_SkColorType: default: format = GL_RGBA; internalFormat = GL_RGBA; type = GL_UNSIGNED_BYTE; break; } renderState.bindFramebuffer(fbo); // TODO: Use layerPool or something to get this maybe? But since we // need explicit format control we can't currently. // Setup the rendertarget glGenTextures(1, &texture); caches.textureState().activateTexture(0); caches.textureState().bindTexture(texture); glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight, 0, format, type, nullptr); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); { bool requiresFilter; // Draw & readback renderState.setViewport(destWidth, destHeight); renderState.scissor().setEnabled(false); renderState.blend().syncEnabled(); renderState.stencil().disable(); Matrix4 croppedTexTransform(texTransform); if (!srcRect.isEmpty()) { // We flipV to convert to 0,0 top-left for the srcRect // coordinates then flip back to 0,0 bottom-left for // GLES coordinates. croppedTexTransform.multiply(sFlipV); croppedTexTransform.translate(srcRect.left / sourceTexture.width(), srcRect.top / sourceTexture.height(), 0); croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(), srcRect.getHeight() / sourceTexture.height(), 1); croppedTexTransform.multiply(sFlipV); requiresFilter = srcRect.getWidth() != (float)destWidth || srcRect.getHeight() != (float)destHeight; } else { requiresFilter = sourceTexture.width() != (uint32_t)destWidth || sourceTexture.height() != (uint32_t)destHeight; } Glop glop; GlopBuilder(renderState, caches, &glop) .setRoundRectClipState(nullptr) .setMeshTexturedUnitQuad(nullptr) .setFillExternalTexture(sourceTexture, croppedTexTransform, requiresFilter) .setTransform(Matrix4::identity(), TransformFlags::None) .setModelViewMapUnitToRect(Rect(destWidth, destHeight)) .build(); Matrix4 ortho; ortho.loadOrtho(destWidth, destHeight); renderState.render(glop, ortho, false); // TODO: We should convert to linear space when the target is RGBA16F glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels()); bitmap->notifyPixelsChanged(); } // Cleanup caches.textureState().deleteTexture(texture); renderState.deleteFramebuffer(fbo); GL_CHECKPOINT(MODERATE); return CopyResult::Success; } CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) { // If this is a 90 or 270 degree rotation we need to swap width/height // This is a fuzzy way of checking that. if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) { std::swap(imgWidth, imgHeight); } Caches& caches = Caches::getInstance(); 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, eglImage); GLenum status = GL_NO_ERROR; while ((status = glGetError()) != GL_NO_ERROR) { ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status); return CopyResult::UnknownError; } Texture sourceTexture(caches); sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */, GL_TEXTURE_EXTERNAL_OES); CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), sourceTexture, imgTransform, srcRect, bitmap); sourceTexture.deleteTexture(); return copyResult; } bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer, SkBitmap* bitmap) { if (!layer.isRenderable()) { // layer has never been updated by DeferredLayerUpdater, abort copy return false; } return CopyResult::Success == copyTextureInto(Caches::getInstance(), renderThread.renderState(), layer.getTexture(), layer.getTexTransform(), Rect(), bitmap); } } // namespace uirenderer } // namespace android libs/hwui/OpenGLReadback.h→libs/hwui/EglReadback.h +5 −22 Original line number Diff line number Diff line Loading @@ -18,16 +18,15 @@ #include "Readback.h" #include "Matrix.h" #include <EGL/egl.h> #include <EGL/eglext.h> namespace android { namespace uirenderer { class Matrix4; class GlLayer; class OpenGLReadback : public Readback { class EglReadback : public Readback { public: virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) override; Loading @@ -35,8 +34,8 @@ public: SkBitmap* bitmap) override; protected: explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {} virtual ~OpenGLReadback() {} explicit EglReadback(renderthread::RenderThread& thread) : Readback(thread) {} virtual ~EglReadback() {} virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect, Loading @@ -47,21 +46,5 @@ private: const Rect& srcRect, SkBitmap* bitmap); }; 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, GlLayer& 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/pipeline/skia/SkiaOpenGLReadback.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -136,6 +136,8 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4 // 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; } Loading libs/hwui/pipeline/skia/SkiaOpenGLReadback.h +3 −3 Original line number Diff line number Diff line Loading @@ -16,15 +16,15 @@ #pragma once #include "OpenGLReadback.h" #include "EglReadback.h" namespace android { namespace uirenderer { namespace skiapipeline { class SkiaOpenGLReadback : public OpenGLReadback { class SkiaOpenGLReadback : public EglReadback { public: SkiaOpenGLReadback(renderthread::RenderThread& thread) : OpenGLReadback(thread) {} SkiaOpenGLReadback(renderthread::RenderThread& thread) : EglReadback(thread) {} protected: virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, Loading Loading
libs/hwui/Android.bp +1 −2 Original line number Diff line number Diff line Loading @@ -186,7 +186,6 @@ cc_defaults { "renderstate/TextureState.cpp", "renderthread/CacheManager.cpp", "renderthread/CanvasContext.cpp", "renderthread/OpenGLPipeline.cpp", "renderthread/DrawFrameTask.cpp", "renderthread/EglManager.cpp", "renderthread/VulkanManager.cpp", Loading Loading @@ -237,7 +236,7 @@ cc_defaults { "LayerUpdateQueue.cpp", "Matrix.cpp", "OpDumper.cpp", "OpenGLReadback.cpp", "EglReadback.cpp", "Patch.cpp", "PatchCache.cpp", "PathCache.cpp", Loading
libs/hwui/OpenGLReadback.cpp→libs/hwui/EglReadback.cpp +97 −0 Original line number Diff line number Diff line Loading @@ -14,17 +14,10 @@ * limitations under the License. */ #include "OpenGLReadback.h" #include "EglReadback.h" #include "Caches.h" #include "GlLayer.h" #include "GlopBuilder.h" #include "Image.h" #include "renderstate/RenderState.h" #include "renderthread/EglManager.h" #include "utils/GLUtils.h" #include <GLES2/gl2.h> #include <gui/Surface.h> #include <ui/Fence.h> #include <ui/GraphicBuffer.h> Loading @@ -32,7 +25,7 @@ namespace android { namespace uirenderer { CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, CopyResult EglReadback::copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) { ATRACE_CALL(); // Setup the source Loading Loading @@ -62,7 +55,7 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap); } CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) { mRenderThread.eglManager().initialize(); Loading @@ -88,15 +81,11 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, CopyResult copyResult = copyImageInto(sourceImage, texTransform, width, height, 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; } CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) { CopyResult EglReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) { Rect srcRect; Matrix4 transform; transform.loadScale(1, -1, 1); Loading @@ -104,184 +93,5 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, S return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap); } static float sFlipVInit[16] = { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, }; static const Matrix4 sFlipV(sFlipVInit); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// 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(); if (destWidth > caches.maxTextureSize || destHeight > caches.maxTextureSize) { ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d", destWidth, destHeight, caches.maxTextureSize); return CopyResult::DestinationInvalid; } if (bitmap->colorType() == kRGBA_F16_SkColorType && !caches.extensions().hasRenderableFloatTextures()) { ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); return CopyResult::DestinationInvalid; } GLuint fbo = renderState.createFramebuffer(); if (!fbo) { ALOGW("Could not obtain an FBO"); return CopyResult::UnknownError; } GLuint texture; GLenum format; GLenum internalFormat; GLenum type; switch (bitmap->colorType()) { case kAlpha_8_SkColorType: format = GL_ALPHA; internalFormat = GL_ALPHA; type = GL_UNSIGNED_BYTE; break; case kRGB_565_SkColorType: format = GL_RGB; internalFormat = GL_RGB; type = GL_UNSIGNED_SHORT_5_6_5; break; case kARGB_4444_SkColorType: format = GL_RGBA; internalFormat = GL_RGBA; type = GL_UNSIGNED_SHORT_4_4_4_4; break; case kRGBA_F16_SkColorType: format = GL_RGBA; internalFormat = GL_RGBA16F; type = GL_HALF_FLOAT; break; case kN32_SkColorType: default: format = GL_RGBA; internalFormat = GL_RGBA; type = GL_UNSIGNED_BYTE; break; } renderState.bindFramebuffer(fbo); // TODO: Use layerPool or something to get this maybe? But since we // need explicit format control we can't currently. // Setup the rendertarget glGenTextures(1, &texture); caches.textureState().activateTexture(0); caches.textureState().bindTexture(texture); glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight, 0, format, type, nullptr); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); { bool requiresFilter; // Draw & readback renderState.setViewport(destWidth, destHeight); renderState.scissor().setEnabled(false); renderState.blend().syncEnabled(); renderState.stencil().disable(); Matrix4 croppedTexTransform(texTransform); if (!srcRect.isEmpty()) { // We flipV to convert to 0,0 top-left for the srcRect // coordinates then flip back to 0,0 bottom-left for // GLES coordinates. croppedTexTransform.multiply(sFlipV); croppedTexTransform.translate(srcRect.left / sourceTexture.width(), srcRect.top / sourceTexture.height(), 0); croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(), srcRect.getHeight() / sourceTexture.height(), 1); croppedTexTransform.multiply(sFlipV); requiresFilter = srcRect.getWidth() != (float)destWidth || srcRect.getHeight() != (float)destHeight; } else { requiresFilter = sourceTexture.width() != (uint32_t)destWidth || sourceTexture.height() != (uint32_t)destHeight; } Glop glop; GlopBuilder(renderState, caches, &glop) .setRoundRectClipState(nullptr) .setMeshTexturedUnitQuad(nullptr) .setFillExternalTexture(sourceTexture, croppedTexTransform, requiresFilter) .setTransform(Matrix4::identity(), TransformFlags::None) .setModelViewMapUnitToRect(Rect(destWidth, destHeight)) .build(); Matrix4 ortho; ortho.loadOrtho(destWidth, destHeight); renderState.render(glop, ortho, false); // TODO: We should convert to linear space when the target is RGBA16F glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels()); bitmap->notifyPixelsChanged(); } // Cleanup caches.textureState().deleteTexture(texture); renderState.deleteFramebuffer(fbo); GL_CHECKPOINT(MODERATE); return CopyResult::Success; } CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) { // If this is a 90 or 270 degree rotation we need to swap width/height // This is a fuzzy way of checking that. if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) { std::swap(imgWidth, imgHeight); } Caches& caches = Caches::getInstance(); 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, eglImage); GLenum status = GL_NO_ERROR; while ((status = glGetError()) != GL_NO_ERROR) { ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status); return CopyResult::UnknownError; } Texture sourceTexture(caches); sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */, GL_TEXTURE_EXTERNAL_OES); CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), sourceTexture, imgTransform, srcRect, bitmap); sourceTexture.deleteTexture(); return copyResult; } bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer, SkBitmap* bitmap) { if (!layer.isRenderable()) { // layer has never been updated by DeferredLayerUpdater, abort copy return false; } return CopyResult::Success == copyTextureInto(Caches::getInstance(), renderThread.renderState(), layer.getTexture(), layer.getTexTransform(), Rect(), bitmap); } } // namespace uirenderer } // namespace android
libs/hwui/OpenGLReadback.h→libs/hwui/EglReadback.h +5 −22 Original line number Diff line number Diff line Loading @@ -18,16 +18,15 @@ #include "Readback.h" #include "Matrix.h" #include <EGL/egl.h> #include <EGL/eglext.h> namespace android { namespace uirenderer { class Matrix4; class GlLayer; class OpenGLReadback : public Readback { class EglReadback : public Readback { public: virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) override; Loading @@ -35,8 +34,8 @@ public: SkBitmap* bitmap) override; protected: explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {} virtual ~OpenGLReadback() {} explicit EglReadback(renderthread::RenderThread& thread) : Readback(thread) {} virtual ~EglReadback() {} virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect, Loading @@ -47,21 +46,5 @@ private: const Rect& srcRect, SkBitmap* bitmap); }; 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, GlLayer& 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/pipeline/skia/SkiaOpenGLReadback.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -136,6 +136,8 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4 // 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; } Loading
libs/hwui/pipeline/skia/SkiaOpenGLReadback.h +3 −3 Original line number Diff line number Diff line Loading @@ -16,15 +16,15 @@ #pragma once #include "OpenGLReadback.h" #include "EglReadback.h" namespace android { namespace uirenderer { namespace skiapipeline { class SkiaOpenGLReadback : public OpenGLReadback { class SkiaOpenGLReadback : public EglReadback { public: SkiaOpenGLReadback(renderthread::RenderThread& thread) : OpenGLReadback(thread) {} SkiaOpenGLReadback(renderthread::RenderThread& thread) : EglReadback(thread) {} protected: virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform, Loading