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

Commit 71526cbc authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Store VkPipelineCache objects in PipelineCache" into main

parents b384973e 2d43a712
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -182,8 +182,9 @@ public class HardwareRenderer {
    /**
     * Name of the file that holds the shaders cache.
     */
    private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
    private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache";
    private static final String CACHE_PATH_OPENGL_SHADERS = "com.android.opengl.shaders_cache";
    private static final String CACHE_PATH_SKIA_SHADERS = "com.android.skia.shaders_cache";
    private static final String CACHE_PATH_SKIA_PIPELINES = "com.android.skia.pipelines_cache";

    private static int sDensityDpi = 0;

@@ -1296,8 +1297,10 @@ public class HardwareRenderer {
     * @hide
     */
    public static void setupDiskCache(File cacheDir) {
        setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(),
                new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath());
        setupPersistentGraphicsCache(
            new File(cacheDir, CACHE_PATH_OPENGL_SHADERS).getAbsolutePath(),
            new File(cacheDir, CACHE_PATH_SKIA_SHADERS).getAbsolutePath(),
            new File(cacheDir, CACHE_PATH_SKIA_PIPELINES).getAbsolutePath());
    }

    /** @hide */
@@ -1595,7 +1598,8 @@ public class HardwareRenderer {
    protected static native boolean isWebViewOverlaysEnabled();

    /** @hide */
    protected static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
    protected static native void setupPersistentGraphicsCache(
            String openglShaderCachePath, String skiaShaderCachePath, String skiaPipelineCachePath);

    private static native void nRotateProcessStatsBuffer();

+4 −0
Original line number Diff line number Diff line
@@ -664,6 +664,8 @@ cc_defaults {
                "pipeline/skia/ATraceMemoryDump.cpp",
                "pipeline/skia/GLFunctorDrawable.cpp",
                "pipeline/skia/LayerDrawable.cpp",
                "pipeline/skia/PersistentGraphicsCache.cpp",
                "pipeline/skia/PipelineCache.cpp",
                "pipeline/skia/ShaderCache.cpp",
                "pipeline/skia/SkiaGpuPipeline.cpp",
                "pipeline/skia/SkiaMemoryTracer.cpp",
@@ -814,6 +816,8 @@ cc_test {
        "tests/unit/MatrixTests.cpp",
        "tests/unit/OpBufferTests.cpp",
        "tests/unit/PathInterpolatorTests.cpp",
        "tests/unit/PersistentGraphicsCacheTests.cpp",
        "tests/unit/PipelineCacheTests.cpp",
        "tests/unit/RenderEffectCapabilityQueryTests.cpp",
        "tests/unit/RenderNodeDrawableTests.cpp",
        "tests/unit/RenderNodeTests.cpp",
+20 −12
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include <media/NdkImageReader.h>
#include <nativehelper/JNIPlatformHelp.h>
#ifdef __ANDROID__
#include <pipeline/skia/PersistentGraphicsCache.h>
#include <pipeline/skia/ShaderCache.h>
#include <private/EGL/cache.h>
#endif
@@ -945,19 +946,25 @@ static void android_view_ThreadedRenderer_removeObserver(JNIEnv* env, jclass cla
}

// ----------------------------------------------------------------------------
// Shaders
// Persistent graphics cache
// ----------------------------------------------------------------------------

static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
        jstring diskCachePath, jstring skiaDiskCachePath) {
static void android_view_ThreadedRenderer_setupPersistentGraphicsCache(
        JNIEnv* env, jobject clazz, jstring openglShaderCachePath, jstring skiaShaderCachePath,
        jstring skiaPipelineCachePath) {
#ifdef __ANDROID__
    const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
    android::egl_set_cache_filename(cacheArray);
    env->ReleaseStringUTFChars(diskCachePath, cacheArray);

    const char* skiaCacheArray = env->GetStringUTFChars(skiaDiskCachePath, NULL);
    uirenderer::skiapipeline::ShaderCache::get().setFilename(skiaCacheArray);
    env->ReleaseStringUTFChars(skiaDiskCachePath, skiaCacheArray);
    const char* openglShaderCachePathArray = env->GetStringUTFChars(openglShaderCachePath, NULL);
    android::egl_set_cache_filename(openglShaderCachePathArray);
    env->ReleaseStringUTFChars(openglShaderCachePath, openglShaderCachePathArray);

    const char* skiaShaderCachePathArray = env->GetStringUTFChars(skiaShaderCachePath, NULL);
    uirenderer::skiapipeline::ShaderCache::get().setFilename(skiaShaderCachePathArray);
    env->ReleaseStringUTFChars(skiaShaderCachePath, skiaShaderCachePathArray);

    const char* skiaPipelineCachePathArray = env->GetStringUTFChars(skiaPipelineCachePath, NULL);
    uirenderer::skiapipeline::PersistentGraphicsCache::get().initPipelineCache(
            skiaPipelineCachePathArray);
    env->ReleaseStringUTFChars(skiaPipelineCachePath, skiaPipelineCachePathArray);
#endif
}

@@ -1025,8 +1032,9 @@ static const JNINativeMethod gMethods[] = {
         (void*)android_view_ThreadedRenderer_dumpProfileInfo},
        {"nDumpGlobalProfileInfo", "(Ljava/io/FileDescriptor;I)V",
         (void*)android_view_ThreadedRenderer_dumpGlobalProfileInfo},
        {"setupShadersDiskCache", "(Ljava/lang/String;Ljava/lang/String;)V",
         (void*)android_view_ThreadedRenderer_setupShadersDiskCache},
        {"setupPersistentGraphicsCache",
         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
         (void*)android_view_ThreadedRenderer_setupPersistentGraphicsCache},
        {"nAddRenderNode", "(JJZ)V", (void*)android_view_ThreadedRenderer_addRenderNode},
        {"nRemoveRenderNode", "(JJ)V", (void*)android_view_ThreadedRenderer_removeRenderNode},
        {"nDrawRenderNode", "(JJ)V", (void*)android_view_ThreadedRendererd_drawRenderNode},
+156 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.
 */

#include "PersistentGraphicsCache.h"

#include <SkData.h>
#include <SkRefCnt.h>
#include <SkString.h>
#include <ganesh/GrDirectContext.h>
#include <log/log.h>

#include <cstddef>
#include <memory>
#include <string>
#include <utility>

#include "Properties.h"
#include "ShaderCache.h"

#ifdef __linux__
#include <com_android_graphics_hwui_flags.h>
namespace hwui_flags = com::android::graphics::hwui::flags;
#else   // __linux__
namespace hwui_flags {
constexpr bool separate_pipeline_cache() {
    return false;
}
}  // namespace hwui_flags
#endif  // __linux__

namespace {

constexpr size_t kMaxPipelineSizeBytes = 2 * 1024 * 1024;

}  // namespace

namespace android {
namespace uirenderer {
namespace skiapipeline {

PersistentGraphicsCache& PersistentGraphicsCache::get() {
    static PersistentGraphicsCache cache;
    return cache;
}

void PersistentGraphicsCache::initPipelineCache(std::string path,
                                                useconds_t writeThrottleInterval) {
    if (!hwui_flags::separate_pipeline_cache()) {
        return;
    }

    mPipelineCache = std::make_unique<PipelineCache>(std::move(path), writeThrottleInterval);
}

void PersistentGraphicsCache::onVkFrameFlushed(GrDirectContext* context) {
    class RealGrDirectContext : public GrDirectContextWrapper {
    private:
        GrDirectContext* mContext;

    public:
        RealGrDirectContext(GrDirectContext* context) : mContext(context) {}

        bool canDetectNewVkPipelineCacheData() const override {
            return mContext->canDetectNewVkPipelineCacheData();
        }

        bool hasNewVkPipelineCacheData() const override {
            return mContext->hasNewVkPipelineCacheData();
        }

        void storeVkPipelineCacheData(size_t maxSize) override {
            return mContext->storeVkPipelineCacheData(maxSize);
        }

        GrDirectContext* unwrap() const override { return mContext; }
    };

    RealGrDirectContext wrapper(context);
    onVkFrameFlushed(&wrapper);
}

void PersistentGraphicsCache::onVkFrameFlushed(GrDirectContextWrapper* context) {
    if (!hwui_flags::separate_pipeline_cache()) {
        ShaderCache::get().onVkFrameFlushed(context->unwrap());
        return;
    }

    mCanDetectNewVkPipelineCacheData = context->canDetectNewVkPipelineCacheData();
    if (context->hasNewVkPipelineCacheData()) {
        context->storeVkPipelineCacheData(kMaxPipelineSizeBytes);
    }
}

sk_sp<SkData> PersistentGraphicsCache::load(const SkData& key) {
    if (!hwui_flags::separate_pipeline_cache()) {
        return ShaderCache::get().load(key);
    }

    if (mPipelineCache == nullptr) {
        LOG_ALWAYS_FATAL(
                "PersistentGraphicsCache::load: pipeline cache path was not initialized, aborting "
                "load");
        return nullptr;
    }

    auto data = mPipelineCache->tryLoad(key);
    if (data != nullptr) {
        return data;
    }

    return ShaderCache::get().load(key);
}

void PersistentGraphicsCache::store(const SkData& key, const SkData& data,
                                    const SkString& description) {
    if (!hwui_flags::separate_pipeline_cache()) {
        ShaderCache::get().store(key, data, description);
        return;
    }

    if (mPipelineCache == nullptr) {
        LOG_ALWAYS_FATAL(
                "PersistentGraphicsCache::store: pipeline cache path was not initialized, aborting "
                "store");
        return;
    }

    if (mPipelineCache->canStore(description)) {
        if (mCanDetectNewVkPipelineCacheData) {
            mPipelineCache->store(key, data);
        } else if (mLastPipelineCacheSize != data.size()) {
            mPipelineCache->store(key, data);
            mLastPipelineCacheSize = data.size();
        }
        return;
    }

    ShaderCache::get().store(key, data, description);
}

}  // namespace skiapipeline
}  // namespace uirenderer
}  // namespace android
+74 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.
 */

#pragma once

#include <ganesh/GrContextOptions.h>
#include <ganesh/GrDirectContext.h>
#include <sys/types.h>

#include <cstddef>
#include <memory>
#include <string>

#include "PipelineCache.h"

namespace android {
namespace uirenderer {
namespace skiapipeline {

// Delegate persistent cache operations to either the pipeline cache or the shader cache as
// appropriate
class PersistentGraphicsCache : public GrContextOptions::PersistentCache {
    static constexpr useconds_t kDefaultWriteThrottleInterval = 4 * 1000 * 1000;

public:
    static PersistentGraphicsCache& get();

    void initPipelineCache(std::string path,
                           useconds_t writeThrottleInterval = kDefaultWriteThrottleInterval);
    void onVkFrameFlushed(GrDirectContext* context);

    sk_sp<SkData> load(const SkData& key) override;
    void store(const SkData& key, const SkData& data, const SkString& description) override;

private:
    std::unique_ptr<PipelineCache> mPipelineCache;

    // Workarounds for devices without VK_EXT_pipeline_creation_cache_control
    bool mCanDetectNewVkPipelineCacheData;
    size_t mLastPipelineCacheSize;

    // Unit test infrastructure
    class GrDirectContextWrapper {
    public:
        virtual ~GrDirectContextWrapper() = default;

        virtual bool canDetectNewVkPipelineCacheData() const = 0;
        virtual bool hasNewVkPipelineCacheData() const = 0;
        virtual void storeVkPipelineCacheData(size_t maxSize) = 0;

        virtual GrDirectContext* unwrap() const = 0;
    };

    void onVkFrameFlushed(GrDirectContextWrapper* context);

    friend class PersistentGraphicsCacheTestUtils;
};

}  // namespace skiapipeline
}  // namespace uirenderer
}  // namespace android
Loading