blob: ed8e8b2c8eb65dae651f1813c7b1af97ce49c6cb [file] [edit]
//
// Copyright 2026 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// EGLBlobCacheRestartTest:
// Tests that what ANGLE stores through EGL_ANDROID_blob_cache serves a later Display, as it
// serves a later process on Android. The blob cache is util/test_blob_cache, which keeps its
// entries on disk as Android's multifile blob cache does.
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include "util/EGLWindow.h"
#include "util/test_blob_cache.h"
using namespace angle;
namespace
{
constexpr char kEGLExtName[] = "EGL_ANDROID_blob_cache";
class EGLBlobCacheRestartTest : public ANGLETest<>
{
protected:
EGLBlobCacheRestartTest()
{
// A new Display for every SetUp(), so that recreateTestFixture() is a restart: nothing
// ANGLE keeps in memory survives it, only what it stored in the blob cache.
forceNewDisplay();
mCacheDir = CreateTestBlobCacheDirectory();
}
~EGLBlobCacheRestartTest() override { RemoveTestBlobCacheDirectory(mCacheDir); }
void testSetUp() override
{
// Every new Display gets the cache, as Android hands its blob cache to every process.
// Reopening the directory is what a process restart looks like to the cache: it reads back
// what is on disk.
EGLDisplay display = getEGLWindow()->getDisplay();
if (IsEGLDisplayExtensionEnabled(display, kEGLExtName))
{
InitTestBlobCache(display, eglSetBlobCacheFuncsANDROID, mCacheDir,
TestBlobCacheLimits());
EXPECT_EGL_SUCCESS();
}
}
std::string mCacheDir;
};
// A program linked before a restart is loaded from the blob cache after it.
TEST_P(EGLBlobCacheRestartTest, ProgramSurvivesRestart)
{
ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), kEGLExtName));
// ANGLE only caches programs when it supports program binaries.
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_get_program_binary"));
ANGLE_SKIP_TEST_IF(getEGLWindow()->isFeatureEnabled(Feature::DisableProgramCaching));
{
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
// Deleting the program makes sure its binary is cached, rather than waiting on tasks that
// can run past the link.
}
EXPECT_GT(GetTestBlobCacheStats().stores, 0u) << "Nothing was stored in the blob cache";
recreateTestFixture();
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_GT(GetTestBlobCacheStats().hits, 0u)
<< "The restarted Display loaded nothing from the blob cache";
}
} // anonymous namespace
ANGLE_INSTANTIATE_TEST_ES2(EGLBlobCacheRestartTest);