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

Commit eed408ae authored by Alec Mouri's avatar Alec Mouri Committed by Android (Google) Code Review
Browse files

Merge "Introduce a dependency monitor for fences" into main

parents 9373d968 df868baf
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ cc_defaults {
    defaults: [
        "android.hardware.graphics.composer3-ndk_shared",
        "renderengine_defaults",
        "libsurfaceflinger_common_deps",
    ],
    cflags: [
        "-DGL_GLEXT_PROTOTYPES",
@@ -117,7 +118,10 @@ filegroup {
// possible if libskia_renderengine is just pulled into librenderengine via whole_static_libs.
cc_defaults {
    name: "librenderengine_deps",
    defaults: ["skia_renderengine_deps"],
    defaults: [
        "skia_renderengine_deps",
        "libsurfaceflinger_common_deps",
    ],
    static_libs: ["libskia_renderengine"],
}

+1 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ cc_benchmark {
        "android.hardware.graphics.composer3-ndk_shared",
        "librenderengine_deps",
        "surfaceflinger_defaults",
        "libsurfaceflinger_common_deps",
    ],
    srcs: [
        "main.cpp",
@@ -38,7 +39,6 @@ cc_benchmark {
    static_libs: [
        "librenderengine",
        "libshaders",
        "libsurfaceflinger_common",
        "libtonemap",
    ],
    cflags: [
+10 −0
Original line number Diff line number Diff line
@@ -1236,6 +1236,16 @@ void SkiaRenderEngine::drawLayersInternal(
    LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
    auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface));
    trace(drawFence);
    FenceTimePtr fenceTime = FenceTime::makeValid(drawFence);
    for (const auto& layer : layers) {
        if (FlagManager::getInstance().monitor_buffer_fences()) {
            if (layer.source.buffer.buffer) {
                layer.source.buffer.buffer->getBuffer()
                        ->getDependencyMonitor()
                        .addAccessCompletion(fenceTime, "RE");
            }
        }
    }
    resultPromise->set_value(std::move(drawFence));
}

+1 −0
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@ cc_library_shared {

    srcs: [
        "DebugUtils.cpp",
        "DependencyMonitor.cpp",
        "DeviceProductInfo.cpp",
        "DisplayIdentification.cpp",
        "DynamicDisplayInfo.cpp",
+144 −0
Original line number Diff line number Diff line
/*
 * Copyright 2025 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.
 */

// #define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "DependencyMonitor"

#include <ui/DependencyMonitor.h>
#include <ui/Fence.h>
#include <utils/Timers.h>

#include <inttypes.h>

namespace android {

void DependencyMonitor::addIngress(FenceTimePtr fence, std::string annotation) {
    std::lock_guard lock(mMutex);
    resolveLocked();
    if (mDependencies.isFull() && !mDependencies.front().updateSignalTimes(true)) {
        ALOGD("%s: Clobbering unresolved dependencies -- make me bigger!", mToken.c_str());
    }

    auto& entry = mDependencies.next();
    entry.reset(mToken.c_str());
    ALOGV("%" PRId64 "/%s: addIngress at CPU time %" PRId64 " (%s)", mDependencies.back().id,
          mToken.c_str(), systemTime(), annotation.c_str());

    mDependencies.back().ingress = {std::move(fence), std::move(annotation)};
}

void DependencyMonitor::addAccessCompletion(FenceTimePtr fence, std::string annotation) {
    std::lock_guard lock(mMutex);
    if (mDependencies.size() == 0) {
        return;
    }
    ALOGV("%" PRId64 "/%s: addAccessCompletion at CPU time %" PRId64 " (%s)",
          mDependencies.back().id, mToken.c_str(), systemTime(), annotation.c_str());
    mDependencies.back().accessCompletions.emplace_back(std::move(fence), std::move(annotation));
}

void DependencyMonitor::addEgress(FenceTimePtr fence, std::string annotation) {
    std::lock_guard lock(mMutex);
    if (mDependencies.size() == 0) {
        return;
    }
    ALOGV("%" PRId64 "/%s: addEgress at CPU time %" PRId64 " (%s)", mDependencies.back().id,
          mToken.c_str(), systemTime(), annotation.c_str());
    mDependencies.back().egress = {std::move(fence), std::move(annotation)};
}

void DependencyMonitor::resolveLocked() {
    if (mDependencies.size() == 0) {
        return;
    }

    for (size_t i = mDependencies.size(); i > 0; i--) {
        auto& dependencyBlock = mDependencies[i - 1];

        if (dependencyBlock.validated) {
            continue;
        }

        if (!dependencyBlock.updateSignalTimes(false)) {
            break;
        }

        dependencyBlock.validated = true;
        dependencyBlock.checkUnsafeAccess();
    }
}

bool DependencyMonitor::DependencyBlock::updateSignalTimes(bool excludeIngress) {
    if (egress.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
        return false;
    }

    if (!excludeIngress && ingress.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
        return false;
    }

    for (auto& accessCompletion : accessCompletions) {
        if (accessCompletion.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
            return false;
        }
    }

    return true;
}

void DependencyMonitor::DependencyBlock::checkUnsafeAccess() const {
    const nsecs_t egressTime = egress.fence->getCachedSignalTime();
    const nsecs_t ingressTime = ingress.fence->getCachedSignalTime();

    ALOGV_IF(egressTime != Fence::SIGNAL_TIME_INVALID,
             "%" PRId64 "/%s: Egress time: %" PRId64 " (%s)", token, id, egressTime,
             egress.annotation.c_str());
    ALOGV_IF(Fence::isValidTimestamp(egressTime) && Fence::isValidTimestamp(ingressTime) &&
                     egressTime < ingressTime,
             "%" PRId64 "/%s: Detected egress before ingress!: %" PRId64 " (%s) < %" PRId64 " (%s)",
             id, token, egressTime, egress.annotation, ingressTime, ingress.annotation.c_str());

    for (auto& accessCompletion : accessCompletions) {
        const nsecs_t accessCompletionTime = accessCompletion.fence->getCachedSignalTime();
        if (!Fence::isValidTimestamp(accessCompletionTime)) {
            ALOGI("%" PRId64 "/%s: Detected invalid access completion! <%s>", id, token,
                  accessCompletion.annotation.c_str());
            continue;
        } else {
            ALOGV("%" PRId64 "/%s: Access completion time: %" PRId64 " <%s>", id, token,
                  accessCompletionTime, accessCompletion.annotation.c_str());
        }

        ALOGI_IF(Fence::isValidTimestamp(egressTime) && accessCompletionTime > egressTime,
                 "%" PRId64 "/%s: Detected access completion after egress!: %" PRId64
                 " (%s) > %" PRId64 " (%s)",
                 id, token, accessCompletionTime, accessCompletion.annotation.c_str(), egressTime,
                 egress.annotation.c_str());

        ALOGI_IF(Fence::isValidTimestamp(ingressTime) && accessCompletionTime < ingressTime,
                 "%" PRId64 "/%s: Detected access completion prior to ingress!: %" PRId64
                 " (%s) < %" PRId64 " (%s)",
                 id, token, accessCompletionTime, accessCompletion.annotation.c_str(), ingressTime,
                 ingress.annotation.c_str());
    }

    ALOGV_IF(ingressTime != Fence::SIGNAL_TIME_INVALID,
             "%" PRId64 "/%s: Ingress time: %" PRId64 " (%s)", id, token, ingressTime,
             ingress.annotation.c_str());
}

} // namespace android
 No newline at end of file
Loading