diff options
Diffstat (limited to 'libs/hwui/DeferredLayerUpdater.cpp')
-rw-r--r-- | libs/hwui/DeferredLayerUpdater.cpp | 138 |
1 files changed, 119 insertions, 19 deletions
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 3bee3018d36e..67d8c07e61de 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -15,8 +15,20 @@ */ #include "DeferredLayerUpdater.h" +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +// TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead. +#include <surfacetexture/surface_texture_platform.h> +#include "AutoBackendTextureRelease.h" +#include "Matrix.h" +#include "Properties.h" #include "renderstate/RenderState.h" -#include "utils/PaintUtils.h" +#include "renderthread/EglManager.h" +#include "renderthread/RenderThread.h" +#include "renderthread/VulkanManager.h" + +using namespace android::uirenderer::renderthread; namespace android { namespace uirenderer { @@ -24,7 +36,7 @@ namespace uirenderer { DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState) : mRenderState(renderState) , mBlend(false) - , mSurfaceTexture(nullptr) + , mSurfaceTexture(nullptr, [](ASurfaceTexture*) {}) , mTransform(nullptr) , mGLContextAttached(false) , mUpdateTexImage(false) @@ -38,6 +50,14 @@ DeferredLayerUpdater::~DeferredLayerUpdater() { destroyLayer(); } +void DeferredLayerUpdater::setSurfaceTexture(AutoTextureRelease&& consumer) { + mSurfaceTexture = std::move(consumer); + + GLenum target = ASurfaceTexture_getCurrentTextureTarget(mSurfaceTexture.get()); + LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES, + "set unsupported SurfaceTexture with target %x", target); +} + void DeferredLayerUpdater::onContextDestroyed() { destroyLayer(); } @@ -48,13 +68,15 @@ void DeferredLayerUpdater::destroyLayer() { } if (mSurfaceTexture.get() && mGLContextAttached) { - mSurfaceTexture->detachFromView(); + ASurfaceTexture_releaseConsumerOwnership(mSurfaceTexture.get()); mGLContextAttached = false; } mLayer->postDecStrong(); mLayer = nullptr; + + mImageSlots.clear(); } void DeferredLayerUpdater::setPaint(const SkPaint* paint) { @@ -67,6 +89,35 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) { } } +static status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, EGLDisplay* display, + int* releaseFence, void* handle) { + *display = EGL_NO_DISPLAY; + RenderState* renderState = (RenderState*)handle; + status_t err; + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { + EglManager& eglManager = renderState->getRenderThread().eglManager(); + *display = eglManager.eglDisplay(); + err = eglManager.createReleaseFence(useFenceSync, eglFence, releaseFence); + } else { + err = renderState->getRenderThread().vulkanManager().createReleaseFence( + releaseFence, renderState->getRenderThread().getGrContext()); + } + return err; +} + +static status_t fenceWait(int fence, void* handle) { + // Wait on the producer fence for the buffer to be ready. + status_t err; + RenderState* renderState = (RenderState*)handle; + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { + err = renderState->getRenderThread().eglManager().fenceWait(fence); + } else { + err = renderState->getRenderThread().vulkanManager().fenceWait( + fence, renderState->getRenderThread().getGrContext()); + } + return err; +} + void DeferredLayerUpdater::apply() { if (!mLayer) { mLayer = new Layer(mRenderState, mColorFilter, mAlpha, mMode); @@ -79,24 +130,36 @@ void DeferredLayerUpdater::apply() { if (!mGLContextAttached) { mGLContextAttached = true; mUpdateTexImage = true; - mSurfaceTexture->attachToView(); + ASurfaceTexture_takeConsumerOwnership(mSurfaceTexture.get()); } if (mUpdateTexImage) { mUpdateTexImage = false; - sk_sp<SkImage> layerImage; - SkMatrix textureTransform; - bool queueEmpty = true; - // If the SurfaceTexture queue is in synchronous mode, need to discard all - // but latest frame. Since we can't tell which mode it is in, - // do this unconditionally. - do { - layerImage = mSurfaceTexture->dequeueImage(textureTransform, &queueEmpty, - mRenderState); - } while (layerImage.get() && (!queueEmpty)); - if (layerImage.get()) { - // force filtration if buffer size != layer size - bool forceFilter = mWidth != layerImage->width() || mHeight != layerImage->height(); - updateLayer(forceFilter, textureTransform, layerImage); + float transformMatrix[16]; + android_dataspace dataspace; + int slot; + bool newContent = false; + // Note: ASurfaceTexture_dequeueBuffer discards all but the last frame. This + // is necessary if the SurfaceTexture queue is in synchronous mode, and we + // cannot tell which mode it is in. + AHardwareBuffer* hardwareBuffer = ASurfaceTexture_dequeueBuffer( + mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &newContent, + createReleaseFence, fenceWait, &mRenderState); + + if (hardwareBuffer) { + sk_sp<SkImage> layerImage = mImageSlots[slot].createIfNeeded( + hardwareBuffer, dataspace, newContent, + mRenderState.getRenderThread().getGrContext()); + // unref to match the ref added by ASurfaceTexture_dequeueBuffer. eglCreateImageKHR + // (invoked by createIfNeeded) will add a ref to the AHardwareBuffer. + AHardwareBuffer_release(hardwareBuffer); + if (layerImage.get()) { + SkMatrix textureTransform; + mat4(transformMatrix).copyTo(textureTransform); + // force filtration if buffer size != layer size + bool forceFilter = + mWidth != layerImage->width() || mHeight != layerImage->height(); + updateLayer(forceFilter, textureTransform, layerImage); + } } } @@ -108,7 +171,7 @@ void DeferredLayerUpdater::apply() { } void DeferredLayerUpdater::updateLayer(bool forceFilter, const SkMatrix& textureTransform, - const sk_sp<SkImage>& layerImage) { + const sk_sp<SkImage>& layerImage) { mLayer->setBlend(mBlend); mLayer->setForceFilter(forceFilter); mLayer->setSize(mWidth, mHeight); @@ -123,5 +186,42 @@ void DeferredLayerUpdater::detachSurfaceTexture() { } } +sk_sp<SkImage> DeferredLayerUpdater::ImageSlot::createIfNeeded(AHardwareBuffer* buffer, + android_dataspace dataspace, + bool forceCreate, + GrContext* context) { + if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace || + forceCreate || mBuffer != buffer) { + if (buffer != mBuffer) { + clear(); + } + + if (!buffer) { + return nullptr; + } + + if (!mTextureRelease) { + mTextureRelease = new AutoBackendTextureRelease(context, buffer); + } else { + mTextureRelease->newBufferContent(context); + } + + mDataspace = dataspace; + mBuffer = buffer; + mTextureRelease->makeImage(buffer, dataspace, context); + } + return mTextureRelease ? mTextureRelease->getImage() : nullptr; +} + +void DeferredLayerUpdater::ImageSlot::clear() { + if (mTextureRelease) { + // The following unref counteracts the initial mUsageCount of 1, set by default initializer. + mTextureRelease->unref(true); + mTextureRelease = nullptr; + } + + mBuffer = nullptr; +} + } /* namespace uirenderer */ } /* namespace android */ |