Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d7c5617 authored by Alec Mouri's avatar Alec Mouri
Browse files

[RenderEngine] relax locking conditions of image cache.

RenderEngine::drawLayers is currently only called on the main thread,
and layers should not be destroyed while the main thread is running, so
we don't need to lock during the entirety of rendering.

Note that with this change there is still some jank because GPU
rendering does take a long time, but it's not nearly as bad as before.

Bug: 136806342
Test: open photos a bunch of times
Change-Id: I66d52c07f31ccf350dec4df665364868350e13c0
parent 769ab6f9
Loading
Loading
Loading
Loading
+145 −145
Original line number Original line Diff line number Diff line
@@ -614,54 +614,18 @@ void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& i
    }
    }
}
}


status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
    std::lock_guard<std::mutex> lock(mRenderingMutex);
    return cacheExternalTextureBufferLocked(buffer);
}

status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
                                                     const sp<GraphicBuffer>& buffer,
                                                     const sp<GraphicBuffer>& buffer,
                                                     const sp<Fence>& bufferFence) {
                                                     const sp<Fence>& bufferFence) {
    std::lock_guard<std::mutex> lock(mRenderingMutex);
    return bindExternalTextureBufferLocked(texName, buffer, bufferFence);
}

status_t GLESRenderEngine::cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer) {
    if (buffer == nullptr) {
        return BAD_VALUE;
    }

    ATRACE_CALL();

    if (mImageCache.count(buffer->getId()) > 0) {
        return NO_ERROR;
    }

    std::unique_ptr<Image> newImage = createImage();

    bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
                                                   buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
    if (!created) {
        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
              buffer->getPixelFormat());
        return NO_INIT;
    }
    mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));

    return NO_ERROR;
}

status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName,
                                                           const sp<GraphicBuffer>& buffer,
                                                           const sp<Fence>& bufferFence) {
    ATRACE_CALL();
    ATRACE_CALL();
    status_t cacheResult = cacheExternalTextureBufferLocked(buffer);
    status_t cacheResult = cacheExternalTextureBuffer(buffer);


    if (cacheResult != NO_ERROR) {
    if (cacheResult != NO_ERROR) {
        return cacheResult;
        return cacheResult;
    }
    }


    {
        std::lock_guard<std::mutex> lock(mRenderingMutex);
        auto cachedImage = mImageCache.find(buffer->getId());
        auto cachedImage = mImageCache.find(buffer->getId());


        if (cachedImage == mImageCache.end()) {
        if (cachedImage == mImageCache.end()) {
@@ -671,6 +635,7 @@ status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName,
        }
        }


        bindExternalTextureImage(texName, *cachedImage->second);
        bindExternalTextureImage(texName, *cachedImage->second);
    }


    // Wait for the new buffer to be ready.
    // Wait for the new buffer to be ready.
    if (bufferFence != nullptr && bufferFence->isValid()) {
    if (bufferFence != nullptr && bufferFence->isValid()) {
@@ -696,6 +661,45 @@ status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName,
    return NO_ERROR;
    return NO_ERROR;
}
}


status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
    if (buffer == nullptr) {
        return BAD_VALUE;
    }

    {
        std::lock_guard<std::mutex> lock(mRenderingMutex);
        if (mImageCache.count(buffer->getId()) > 0) {
            // If there's already an image then fail fast here.
            return NO_ERROR;
        }
    }
    ATRACE_CALL();

    // Create the image without holding a lock so that we don't block anything.
    std::unique_ptr<Image> newImage = createImage();

    bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
                                                   buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
    if (!created) {
        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
              buffer->getPixelFormat());
        return NO_INIT;
    }

    {
        std::lock_guard<std::mutex> lock(mRenderingMutex);
        if (mImageCache.count(buffer->getId()) > 0) {
            // In theory it's possible for another thread to recache the image,
            // so bail out if another thread won.
            return NO_ERROR;
        }
        mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
    }

    return NO_ERROR;
}

void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
    std::lock_guard<std::mutex> lock(mRenderingMutex);
    std::lock_guard<std::mutex> lock(mRenderingMutex);
    const auto& cachedImage = mImageCache.find(bufferId);
    const auto& cachedImage = mImageCache.find(bufferId);
@@ -889,9 +893,6 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }


    {
        std::lock_guard<std::mutex> lock(mRenderingMutex);

    BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
    BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);


    if (fbo.getStatus() != NO_ERROR) {
    if (fbo.getStatus() != NO_ERROR) {
@@ -943,7 +944,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
            isOpaque = layer.source.buffer.isOpaque;
            isOpaque = layer.source.buffer.isOpaque;


            sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
            sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
                bindExternalTextureBufferLocked(layer.source.buffer.textureName, gBuf,
            bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
                                      layer.source.buffer.fence);
                                      layer.source.buffer.fence);


            usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
            usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
@@ -1009,7 +1010,6 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
    }
    }


    checkErrors();
    checkErrors();
    }
    return NO_ERROR;
    return NO_ERROR;
}
}


+1 −11
Original line number Original line Diff line number Diff line
@@ -85,8 +85,7 @@ public:
    bool useProtectedContext(bool useProtectedContext) override;
    bool useProtectedContext(bool useProtectedContext) override;
    status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
    status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
                        ANativeWindowBuffer* buffer, const bool useFramebufferCache,
                        ANativeWindowBuffer* buffer, const bool useFramebufferCache,
                        base::unique_fd&& bufferFence, base::unique_fd* drawFence)
                        base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
            EXCLUDES(mRenderingMutex) override;


    // internal to RenderEngine
    // internal to RenderEngine
    EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
    EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
@@ -220,15 +219,6 @@ private:
    // multiple threads is guaranteed thread-safe.
    // multiple threads is guaranteed thread-safe.
    std::mutex mRenderingMutex;
    std::mutex mRenderingMutex;


    // See bindExternalTextureBuffer above, but requiring that mRenderingMutex
    // is held.
    status_t bindExternalTextureBufferLocked(uint32_t texName, const sp<GraphicBuffer>& buffer,
                                             const sp<Fence>& fence) REQUIRES(mRenderingMutex);
    // See cacheExternalTextureBuffer above, but requiring that mRenderingMutex
    // is held.
    status_t cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer)
            REQUIRES(mRenderingMutex);

    std::unique_ptr<Framebuffer> mDrawingBuffer;
    std::unique_ptr<Framebuffer> mDrawingBuffer;


    class FlushTracer {
    class FlushTracer {
+11 −0
Original line number Original line Diff line number Diff line
@@ -176,6 +176,17 @@ public:
    // should be called for every display that needs to be rendered via the GPU.
    // should be called for every display that needs to be rendered via the GPU.
    // @param display The display-wide settings that should be applied prior to
    // @param display The display-wide settings that should be applied prior to
    // drawing any layers.
    // drawing any layers.
    //
    // Assumptions when calling this method:
    // 1. There is exactly one caller - i.e. multi-threading is not supported.
    // 2. Additional threads may be calling the {bind,cache}ExternalTexture
    // methods above. But the main thread is responsible for holding resources
    // such that Image destruction does not occur while this method is called.
    //
    // TODO(b/136806342): This should behavior should ideally be fixed since
    // the above two assumptions are brittle, as conditional thread safetyness
    // may be insufficient when maximizing rendering performance in the future.
    //
    // @param layers The layers to draw onto the display, in Z-order.
    // @param layers The layers to draw onto the display, in Z-order.
    // @param buffer The buffer which will be drawn to. This buffer will be
    // @param buffer The buffer which will be drawn to. This buffer will be
    // ready once drawFence fires.
    // ready once drawFence fires.