Commit 7df7fc7f by Shahbaz Youssefi Committed by Angle LUCI CQ

Tests: Add support for --renderdoc

This change adds support for a new flag namely `--renderdoc` to end2end and deqp tests. With this flag, each test automatically starts and ends a frame capture in renderdoc, working around an issue where renderdoc refuses to capture a test frame that doesn't start or end with a swap. With end2end tests, the capture starts before test set up, and ends after test tear down. With deqp tests, it starts before init, ends and restarts after each test iteration and ends after deinit. Bug: angleproject:6072 Change-Id: Ib41b816aff121bf922d9147044cc363c33a62181 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2971835 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 9412ac9c
......@@ -70,8 +70,12 @@ class Library : angle::NonCopyable
// (e.g. opengl32.dll)
enum class SearchType
{
// Try to find the library in the application directory
ApplicationDir,
SystemDir
// Load the library from the system directories
SystemDir,
// Get a reference to an already loaded shared library.
AlreadyLoaded,
};
Library *OpenSharedLibrary(const char *libraryName, SearchType searchType);
......
......@@ -78,7 +78,9 @@ std::string GetModuleDirectory()
class PosixLibrary : public Library
{
public:
PosixLibrary(const std::string &fullPath) : mModule(dlopen(fullPath.c_str(), RTLD_NOW)) {}
PosixLibrary(const std::string &fullPath, int extraFlags)
: mModule(dlopen(fullPath.c_str(), RTLD_NOW | extraFlags))
{}
~PosixLibrary() override
{
......@@ -117,17 +119,23 @@ Library *OpenSharedLibrary(const char *libraryName, SearchType searchType)
#endif
}
int extraFlags = 0;
if (searchType == SearchType::AlreadyLoaded)
{
extraFlags = RTLD_NOLOAD;
}
std::string fullPath = directory + libraryName + "." + GetSharedLibraryExtension();
#if ANGLE_PLATFORM_IOS
// On iOS, dlopen needs a suffix on the framework name to work.
fullPath = fullPath + "/" + libraryName;
#endif
return new PosixLibrary(fullPath);
return new PosixLibrary(fullPath, extraFlags);
}
Library *OpenSharedLibraryWithExtension(const char *libraryName)
{
return new PosixLibrary(libraryName);
return new PosixLibrary(libraryName, 0);
}
bool IsDirectory(const char *filename)
......
......@@ -50,6 +50,9 @@ class Win32Library : public Library
case SearchType::SystemDir:
mModule = LoadLibraryExA(libraryName, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
break;
case SearchType::AlreadyLoaded:
mModule = GetModuleHandleA(libraryName);
break;
}
}
......
......@@ -44,6 +44,7 @@ class UwpLibrary : public Library
mModule = LoadPackagedLibrary(wideBuffer.c_str(), 0);
break;
case SearchType::SystemDir:
case SearchType::AlreadyLoaded:
// Not supported in UWP
break;
}
......
......@@ -104,6 +104,9 @@ template("angle_common_test_utils") {
"//third_party/googletest:gtest",
]
sources = [
"$angle_root/third_party/renderdoc/src/renderdoc_app.h",
"test_utils/RenderDoc.cpp",
"test_utils/RenderDoc.h",
"test_utils/angle_test_configs.cpp",
"test_utils/angle_test_configs.h",
"test_utils/angle_test_instantiate.cpp",
......
......@@ -116,6 +116,7 @@ constexpr char kANGLEEGLString[] = "--use-angle=";
constexpr char kANGLEPreRotation[] = "--emulated-pre-rotation=";
constexpr char kdEQPCaseString[] = "--deqp-case=";
constexpr char kVerboseString[] = "--verbose";
constexpr char kRenderDocString[] = "--renderdoc";
std::array<char, 500> gCaseStringBuffer;
......@@ -133,6 +134,8 @@ constexpr uint32_t kDefaultPreRotation = 0;
const APIInfo *gInitAPI = nullptr;
uint32_t gPreRotation = kDefaultPreRotation;
bool gEnableRenderDocCapture = false;
constexpr const char gdEQPEGLConfigNameString[] = "--deqp-gl-config-name=";
constexpr const char gdEQPLogImagesString[] = "--deqp-log-images=";
......@@ -555,7 +558,8 @@ void dEQPTest<TestModuleIndex>::SetUpTestCase()
// Init the platform.
if (!deqp_libtester_init_platform(static_cast<int>(argv.size()), argv.data(),
reinterpret_cast<void *>(&HandlePlatformError), gPreRotation))
reinterpret_cast<void *>(&HandlePlatformError), gPreRotation,
gEnableRenderDocCapture))
{
std::cout << "Aborting test due to dEQP initialization error." << std::endl;
exit(1);
......@@ -758,6 +762,10 @@ void InitTestHarness(int *argc, char **argv)
{
HandleLogImages(argv[argIndex] + strlen(gdEQPLogImagesString));
}
else if (strncmp(argv[argIndex], kRenderDocString, strlen(kRenderDocString)) == 0)
{
gEnableRenderDocCapture = true;
}
argIndex++;
}
......
......@@ -42,7 +42,8 @@ ANGLE_LIBTESTER_EXPORT int deqp_libtester_main(int argc, const char *argv[]);
ANGLE_LIBTESTER_EXPORT bool deqp_libtester_init_platform(int argc,
const char *argv[],
void *logErrorFunc,
uint32_t preRotation);
uint32_t preRotation,
bool enableRenderDocCapture);
ANGLE_LIBTESTER_EXPORT void deqp_libtester_shutdown_platform();
ANGLE_LIBTESTER_EXPORT dEQPTestResult deqp_libtester_run(const char *caseName);
......
......@@ -51,7 +51,8 @@ std::string GetLogFileName(std::string deqpDataDir)
ANGLE_LIBTESTER_EXPORT bool deqp_libtester_init_platform(int argc,
const char *argv[],
void *logErrorFunc,
uint32_t preRotation)
uint32_t preRotation,
bool enableRenderDocCapture)
{
try
{
......@@ -81,7 +82,7 @@ ANGLE_LIBTESTER_EXPORT bool deqp_libtester_init_platform(int argc,
g_log = new tcu::TestLog(GetLogFileName(deqpDataDir).c_str(), g_cmdLine->getLogFlags());
g_testCtx = new tcu::TestContext(*g_platform, *g_archive, *g_log, *g_cmdLine, DE_NULL);
g_root = new tcu::TestPackageRoot(*g_testCtx, tcu::TestPackageRegistry::getSingleton());
g_executor = new tcu::RandomOrderExecutor(*g_root, *g_testCtx);
g_executor = new tcu::RandomOrderExecutor(*g_root, *g_testCtx, enableRenderDocCapture);
}
catch (const std::exception &e)
{
......@@ -95,7 +96,7 @@ ANGLE_LIBTESTER_EXPORT bool deqp_libtester_init_platform(int argc,
// Exported to the tester app.
ANGLE_LIBTESTER_EXPORT int deqp_libtester_main(int argc, const char *argv[])
{
if (!deqp_libtester_init_platform(argc, argv, nullptr, 0))
if (!deqp_libtester_init_platform(argc, argv, nullptr, 0, false))
{
tcu::die("Could not initialize the dEQP platform");
}
......
......@@ -2021,6 +2021,9 @@ deqp_libtester_sources = [
"deqp_support/tcuANGLENativeDisplayFactory.h",
# TODO(jmadill): integrate with dEQP
"$angle_root/third_party/renderdoc/src/renderdoc_app.h",
"deqp_support/tcuRandomOrderExecutor.cpp",
"deqp_support/tcuRandomOrderExecutor.h",
"test_utils/RenderDoc.cpp",
"test_utils/RenderDoc.h",
]
......@@ -38,11 +38,18 @@ using std::vector;
namespace tcu
{
RandomOrderExecutor::RandomOrderExecutor(TestPackageRoot &root, TestContext &testCtx)
RandomOrderExecutor::RandomOrderExecutor(TestPackageRoot &root,
TestContext &testCtx,
bool enableRenderDocCapture)
: m_testCtx(testCtx), m_inflater(testCtx)
{
m_nodeStack.push_back(NodeStackEntry(&root));
root.getChildren(m_nodeStack[0].children);
if (enableRenderDocCapture)
{
mRenderDoc.attach();
}
}
RandomOrderExecutor::~RandomOrderExecutor(void)
......@@ -196,6 +203,7 @@ tcu::TestStatus RandomOrderExecutor::executeInner(TestCase *testCase, const std:
// Initialize, will return immediately if fails
try
{
mRenderDoc.startFrame();
m_caseExecutor->init(testCase, casePath);
}
catch (const std::bad_alloc &)
......@@ -217,6 +225,8 @@ tcu::TestStatus RandomOrderExecutor::executeInner(TestCase *testCase, const std:
return TestStatus(QP_TEST_RESULT_FAIL, e.getMessage());
}
bool isFirstFrameBeingCaptured = true;
// Execute
for (;;)
{
......@@ -226,6 +236,15 @@ tcu::TestStatus RandomOrderExecutor::executeInner(TestCase *testCase, const std:
try
{
// Make every iteration produce one renderdoc frame. Include the init code in the first
// frame, and the deinit code in the last frame.
if (!isFirstFrameBeingCaptured)
{
mRenderDoc.endFrame();
mRenderDoc.startFrame();
}
isFirstFrameBeingCaptured = false;
iterateResult = m_caseExecutor->iterate(testCase);
}
catch (const std::bad_alloc &)
......@@ -259,6 +278,7 @@ tcu::TestStatus RandomOrderExecutor::executeInner(TestCase *testCase, const std:
try
{
m_caseExecutor->deinit(testCase);
mRenderDoc.endFrame();
}
catch (const tcu::Exception &e)
{
......
......@@ -27,13 +27,15 @@
#include "deUniquePtr.hpp"
#include "tcuTestHierarchyIterator.hpp"
#include "tests/test_utils/RenderDoc.h"
namespace tcu
{
class RandomOrderExecutor
{
public:
RandomOrderExecutor(TestPackageRoot &root, TestContext &testCtx);
RandomOrderExecutor(TestPackageRoot &root, TestContext &testCtx, bool enableRenderDocCapture);
~RandomOrderExecutor(void);
TestStatus execute(const std::string &path);
......@@ -59,6 +61,8 @@ class RandomOrderExecutor
std::vector<NodeStackEntry> m_nodeStack;
de::MovePtr<TestCaseExecutor> m_caseExecutor;
RenderDoc mRenderDoc;
};
} // namespace tcu
......
......@@ -354,6 +354,7 @@ constexpr char kReuseDisplays[] = "--reuse-displays";
constexpr char kEnableANGLEPerTestCaptureLabel[] = "--angle-per-test-capture-label";
constexpr char kBatchId[] = "--batch-id=";
constexpr char kDelayTestStart[] = "--delay-test-start=";
constexpr char kRenderDoc[] = "--renderdoc";
void SetupEnvironmentVarsForCaptureReplay()
{
......@@ -378,6 +379,8 @@ void SetTestStartDelay(const char *testStartDelay)
gTestStartDelaySeconds = std::stoi(testStartDelay);
}
bool gEnableRenderDocCapture = false;
// static
std::array<Vector3, 6> ANGLETestBase::GetQuadVertices()
{
......@@ -425,6 +428,11 @@ ANGLETestBase::ANGLETestBase(const PlatformParameters &params)
#endif
}
if (gEnableRenderDocCapture)
{
mRenderDoc.attach();
}
auto iter = gFixtures.find(withMethods);
if (iter != gFixtures.end())
{
......@@ -684,6 +692,8 @@ void ANGLETestBase::ANGLETestSetUp()
glViewport(0, 0, mWidth, mHeight);
mIsSetUp = true;
mRenderDoc.startFrame();
}
void ANGLETestBase::ANGLETestTearDown()
......@@ -699,12 +709,15 @@ void ANGLETestBase::ANGLETestTearDown()
if (mCurrentParams->noFixture || !mFixture->osWindow->valid())
{
mRenderDoc.endFrame();
return;
}
swapBuffers();
mFixture->osWindow->messageLoop();
mRenderDoc.endFrame();
if (mFixture->eglWindow)
{
checkD3D11SDKLayersMessages();
......@@ -1522,5 +1535,9 @@ void ANGLEProcessTestArgs(int *argc, char *argv[])
{
SetTestStartDelay(argv[argIndex] + strlen(kDelayTestStart));
}
else if (strncmp(argv[argIndex], kRenderDoc, strlen(kRenderDoc)) == 0)
{
gEnableRenderDocCapture = true;
}
}
}
......@@ -14,6 +14,7 @@
#include <algorithm>
#include <array>
#include "RenderDoc.h"
#include "angle_test_configs.h"
#include "angle_test_platform.h"
#include "common/angleutils.h"
......@@ -584,6 +585,8 @@ class ANGLETestBase
const angle::PlatformParameters *mCurrentParams;
TestFixture *mFixture;
RenderDoc mRenderDoc;
// Workaround for NVIDIA not being able to share a window with OpenGL and Vulkan.
static Optional<EGLint> mLastRendererType;
static Optional<angle::GLESDriverType> mLastLoadedDriver;
......
//
// Copyright 2021 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.
//
// RenderDoc:
// Connection to renderdoc for capturing tests through its API.
//
#include "RenderDoc.h"
#include "common/angleutils.h"
#include "common/debug.h"
RenderDoc::RenderDoc() : mRenderDocModule(nullptr), mApi(nullptr) {}
RenderDoc::~RenderDoc()
{
SafeDelete(mRenderDocModule);
}
#if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX) || \
defined(ANGLE_PLATFORM_WINDOWS)
# include "third_party/renderdoc/src/renderdoc_app.h"
# if defined(ANGLE_PLATFORM_WINDOWS)
constexpr char kRenderDocModuleName[] = "renderdoc";
# elif defined(ANGLE_PLATFORM_ANDROID)
constexpr char kRenderDocModuleName[] = "libVkLayer_GLES_RenderDoc";
# else
constexpr char kRenderDocModuleName[] = "librenderdoc";
# endif
void RenderDoc::attach()
{
mRenderDocModule = OpenSharedLibrary(kRenderDocModuleName, angle::SearchType::AlreadyLoaded);
if (mRenderDocModule == nullptr || mRenderDocModule->getNative() == nullptr)
{
return;
}
void *getApi = mRenderDocModule->getSymbol("RENDERDOC_GetAPI");
if (getApi == nullptr)
{
return;
}
int result = reinterpret_cast<pRENDERDOC_GetAPI>(getApi)(eRENDERDOC_API_Version_1_1_2, &mApi);
if (result != 1)
{
ERR() << "RenderDoc module is present but API 1.1.2 is unavailable";
mApi = nullptr;
}
}
void RenderDoc::startFrame()
{
if (mApi)
{
static_cast<RENDERDOC_API_1_1_2 *>(mApi)->StartFrameCapture(nullptr, nullptr);
}
}
void RenderDoc::endFrame()
{
if (mApi)
{
static_cast<RENDERDOC_API_1_1_2 *>(mApi)->EndFrameCapture(nullptr, nullptr);
}
}
#else // defiend(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX) ||
// defined(ANGLE_PLATFORM_WINDOWS)
// Stub out the implementation on unsupported platforms.
void RenderDoc::attach()
{
mApi = nullptr;
}
void RenderDoc::startFrame() {}
void RenderDoc::endFrame() {}
#endif // defiend(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX) ||
// defined(ANGLE_PLATFORM_WINDOWS)
//
// Copyright 2021 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.
//
// RenderDoc:
// Connection to renderdoc for capturing tests through its API.
//
#ifndef TESTS_TEST_UTILS_RENDERDOC_H_
#define TESTS_TEST_UTILS_RENDERDOC_H_
#include "common/system_utils.h"
class RenderDoc
{
public:
RenderDoc();
~RenderDoc();
void attach();
void startFrame();
void endFrame();
private:
angle::Library *mRenderDocModule;
void *mApi;
};
#endif // TESTS_TEST_UTILS_RENDERDOC_H_
Name: RenderDoc API Header
URL: https://raw.githubusercontent.com/baldurk/renderdoc/v1.1/renderdoc/api/app/renderdoc_app.h
License: MIT
License File: NOT_SHIPPED
Security Critical: no
Description:
Header file for RenderDoc's in-app capture API.
Local modifications:
None
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment