backend: add two command line arguments to backend test (#9329)
`--headless_only` Headless-only mode indicates that we will only use headless swapchains. This is particularly useful if we want to test in a CI (continuous integration) environment. `--ci` Having CONTINUOUS_INTEGRATION as an OS will allow us to have CI-only temporary exceptions. Though it's expected that some exceptions will be unfixable and will remain as workarounds.
This commit is contained in:
@@ -23,13 +23,17 @@
|
||||
|
||||
namespace test {
|
||||
|
||||
Backend parseArgumentsForBackend(int argc, char* argv[]) {
|
||||
Backend backend = Backend::OPENGL;
|
||||
TestArguments parseArguments(int argc, char* argv[]) {
|
||||
TestArguments arguments = {};
|
||||
arguments.backend = Backend::OPENGL;
|
||||
|
||||
// The first colon in OPTSTR turns on silent error reporting. This is important, as the
|
||||
// arguments may also contain gtest parameters we don't know about.
|
||||
static constexpr const char* OPTSTR = ":a:";
|
||||
static constexpr const char* OPTSTR = ":a:kc";
|
||||
static const struct option OPTIONS[] = {
|
||||
{ "api", required_argument, nullptr, 'a' },
|
||||
{ "headless_only", no_argument, nullptr, 'k' },
|
||||
{ "ci", no_argument, nullptr, 'c' },
|
||||
{ nullptr, 0, nullptr, 0 } // termination of the option list
|
||||
};
|
||||
|
||||
@@ -41,13 +45,13 @@ Backend parseArgumentsForBackend(int argc, char* argv[]) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
if (arg == "opengl") {
|
||||
backend = Backend::OPENGL;
|
||||
arguments.backend = Backend::OPENGL;
|
||||
} else if (arg == "vulkan") {
|
||||
backend = Backend::VULKAN;
|
||||
arguments.backend = Backend::VULKAN;
|
||||
} else if (arg == "metal") {
|
||||
backend = Backend::METAL;
|
||||
arguments.backend = Backend::METAL;
|
||||
} else if (arg == "webgpu") {
|
||||
backend = Backend::WEBGPU;
|
||||
arguments.backend = Backend::WEBGPU;
|
||||
} else {
|
||||
std::cerr << "Unrecognized target API. Must be 'opengl'|'vulkan'|'metal'|'webgpu'."
|
||||
<< std::endl
|
||||
@@ -55,10 +59,16 @@ Backend parseArgumentsForBackend(int argc, char* argv[]) {
|
||||
<< std::endl;
|
||||
}
|
||||
break;
|
||||
case 'k':
|
||||
arguments.headlessOnly = true;
|
||||
break;
|
||||
case 'c':
|
||||
arguments.isContinuousIntegration = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return backend;
|
||||
return arguments;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -41,6 +41,7 @@ enum class OperatingSystem: uint8_t {
|
||||
LINUX = 2,
|
||||
// Also represents iOS phones.
|
||||
APPLE = 3,
|
||||
CONTINUOUS_INTEGRATION = 4,
|
||||
// TODO: When tests support windows add it here.
|
||||
};
|
||||
|
||||
@@ -73,11 +74,17 @@ void initTests(Backend backend, OperatingSystem operatingSystem, bool isMobile,
|
||||
*/
|
||||
int runTests();
|
||||
|
||||
struct TestArguments {
|
||||
Backend backend;
|
||||
bool headlessOnly = false;
|
||||
bool isContinuousIntegration = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* A utility method that can be invoked by test runners to parse arguments.
|
||||
* Looks through the provided command-line arguments and finds any -a <backend> arguments.
|
||||
*/
|
||||
Backend parseArgumentsForBackend(int argc, char* argv[]);
|
||||
TestArguments parseArguments(int argc, char* argv[]);
|
||||
|
||||
} // namespace test
|
||||
|
||||
|
||||
@@ -43,7 +43,10 @@ std::array<test::Backend, 2> const VALID_BACKENDS{
|
||||
}// namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
auto backend = test::parseArgumentsForBackend(argc, argv);
|
||||
const auto arguments = test::parseArguments(argc, argv);
|
||||
const auto backend = arguments.backend;
|
||||
|
||||
// Note that Linux is headless-only.
|
||||
|
||||
if (!std::any_of(VALID_BACKENDS.begin(), VALID_BACKENDS.end(),
|
||||
[backend](test::Backend validBackend) { return backend == validBackend; })) {
|
||||
@@ -51,6 +54,8 @@ int main(int argc, char* argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
test::initTests(backend, test::OperatingSystem::LINUX, false, argc, argv);
|
||||
const auto operatingSystem = arguments.isContinuousIntegration ?
|
||||
test::OperatingSystem::CONTINUOUS_INTEGRATION : test::OperatingSystem::LINUX;
|
||||
test::initTests(backend, operatingSystem, false, argc, argv);
|
||||
return test::runTests();
|
||||
}
|
||||
|
||||
@@ -32,29 +32,34 @@ test::NativeView getNativeView() {
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||
|
||||
@property test::Backend backend;
|
||||
@property bool headlessOnly;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
NSView* view = [self createView];
|
||||
|
||||
if (self.backend == test::Backend::OPENGL) {
|
||||
nativeView.ptr = (void*) view;
|
||||
if (self.headlessOnly) {
|
||||
nativeView.ptr = nullptr;
|
||||
nativeView.width = test::WINDOW_WIDTH;
|
||||
nativeView.height = test::WINDOW_HEIGHT;
|
||||
} else {
|
||||
NSView* view = [self createView];
|
||||
switch (self.backend) {
|
||||
case test::Backend::OPENGL:
|
||||
nativeView.ptr = (void*) view;
|
||||
break;
|
||||
case test::Backend::METAL:
|
||||
case test::Backend::VULKAN:
|
||||
case test::Backend::WEBGPU:
|
||||
case test::Backend::NOOP:
|
||||
nativeView.ptr = (void*) view.layer;
|
||||
break;
|
||||
}
|
||||
CGSize drawableSize = ((CAMetalLayer*) view.layer).drawableSize;
|
||||
nativeView.width = static_cast<size_t>(drawableSize.width);
|
||||
nativeView.height = static_cast<size_t>(drawableSize.height);
|
||||
}
|
||||
if (self.backend == test::Backend::METAL) {
|
||||
nativeView.ptr = (void*) view.layer;
|
||||
}
|
||||
if (self.backend == test::Backend::VULKAN) {
|
||||
nativeView.ptr = (void*) view.layer;
|
||||
}
|
||||
if (self.backend == test::Backend::WEBGPU) {
|
||||
nativeView.ptr = (void*) view.layer;
|
||||
}
|
||||
CGSize drawableSize = ((CAMetalLayer*) view.layer).drawableSize;
|
||||
nativeView.width = static_cast<size_t>(drawableSize.width);
|
||||
nativeView.height = static_cast<size_t>(drawableSize.height);
|
||||
|
||||
exit(test::runTests());
|
||||
}
|
||||
@@ -100,11 +105,25 @@ test::NativeView getNativeView() {
|
||||
@end
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
auto backend = test::parseArgumentsForBackend(argc, argv);
|
||||
test::initTests(backend, test::OperatingSystem::APPLE, false, argc, argv);
|
||||
AppDelegate* delegate = [AppDelegate new];
|
||||
delegate.backend = backend;
|
||||
const auto arguments = test::parseArguments(argc, argv);
|
||||
const auto operatingSystem = arguments.isContinuousIntegration ?
|
||||
test::OperatingSystem::CONTINUOUS_INTEGRATION : test::OperatingSystem::APPLE;
|
||||
test::initTests(arguments.backend, operatingSystem, false, argc, argv);
|
||||
|
||||
NSApplication* app = [NSApplication sharedApplication];
|
||||
AppDelegate* delegate = [AppDelegate new];
|
||||
delegate.backend = arguments.backend;
|
||||
delegate.headlessOnly = arguments.headlessOnly;
|
||||
[app setDelegate:delegate];
|
||||
|
||||
if (arguments.headlessOnly) {
|
||||
// In headless mode, we don't want to start the NSApplication event loop.
|
||||
// Instead, we can manually "finish" launching the app, which will trigger the tests to run.
|
||||
[app finishLaunching];
|
||||
[delegate applicationDidFinishLaunching:nil];
|
||||
// The line above calls exit(), so we should not reach here.
|
||||
return 0;
|
||||
}
|
||||
|
||||
[app run];
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ TEST_F(BlitTest, ColorMagnify) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = mCleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = mCleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
@@ -222,7 +222,7 @@ TEST_F(BlitTest, ColorMinify) {
|
||||
constexpr int kNumLevels = 3;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = mCleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = mCleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
@@ -371,7 +371,7 @@ TEST_F(BlitTest, Blit2DTextureArray) {
|
||||
constexpr int kDstTexLayer = 0;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = mCleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = mCleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
@@ -437,7 +437,7 @@ TEST_F(BlitTest, BlitRegion) {
|
||||
constexpr int kDstLevel = 0;
|
||||
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = mCleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = mCleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
// Create a source texture.
|
||||
|
||||
@@ -103,7 +103,7 @@ TEST_F(BackendTest, FrameCompletedCallback) {
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create a SwapChain.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
|
||||
int callbackCountA = 0;
|
||||
api.setFrameCompletedCallback(swapChain, nullptr,
|
||||
|
||||
@@ -385,8 +385,7 @@ TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
|
||||
Cleanup cleanup(api);
|
||||
|
||||
// Create a platform-specific SwapChain and make it current.
|
||||
auto swapChain = cleanup.add(
|
||||
api.createSwapChainHeadless(renderTargetSize, renderTargetSize, 0));
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
Shader shader = SharedShaders::makeShader(api, cleanup, ShaderRequest{
|
||||
|
||||
@@ -70,7 +70,7 @@ TEST_F(BackendTest, ScissorViewportRegion) {
|
||||
// executeCommands().
|
||||
{
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
Shader shader = SharedShaders::makeShader(api, cleanup,
|
||||
@@ -149,7 +149,7 @@ TEST_F(BackendTest, ScissorViewportEdgeCases) {
|
||||
// executeCommands().
|
||||
{
|
||||
// Create a SwapChain and make it current. We don't really use it so the res doesn't matter.
|
||||
auto swapChain = cleanup.add(api.createSwapChainHeadless(256, 256, 0));
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
Shader shader = SharedShaders::makeShader(api, cleanup, ShaderRequest{
|
||||
|
||||
@@ -33,8 +33,7 @@ TEST_F(BackendTest, TestTemplate) {
|
||||
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
auto swapChain =
|
||||
cleanup.add(api.createSwapChainHeadless(kRenderTargetSize, kRenderTargetSize, 0));
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
RenderTargetHandle renderTarget = cleanup.add(api.createDefaultRenderTarget());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user