mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-07 06:09:57 +03:00
Perf tests: Add screenshot capture mode.
This adds a "--screenshot-dir" argument to capture screenshots. If we're running with screenshot capture then the test will early exit after the first capture. The screenshots use the same naming pattern as the test name: TracePerfTest.Run/vulkan_trex_200 -> angle_vulkan_trex_200.png Note the screenshot dir is relative to the test binary directory, not the CWD. Also adds a PNG saving utility function. Bug: angleproject:4615 Change-Id: I1de8ae6a6e6892586bb0b743e7b9a842f90f98e5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2184834 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Cody Northrop <cnorthrop@google.com>
This commit is contained in:
@@ -238,7 +238,10 @@ template("angle_perftests_common") {
|
||||
"perf_tests/third_party/perf/perf_test.cc",
|
||||
"perf_tests/third_party/perf/perf_test.h",
|
||||
]
|
||||
deps = [ "$angle_jsoncpp_dir:jsoncpp" ]
|
||||
deps = [
|
||||
"$angle_jsoncpp_dir:jsoncpp",
|
||||
"$angle_root/util:angle_png_utils",
|
||||
]
|
||||
public_deps = [ "${invoker.test_utils}" ]
|
||||
public_configs += [ "${angle_root}:libANGLE_config" ]
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "common/utilities.h"
|
||||
#include "third_party/perf/perf_test.h"
|
||||
#include "third_party/trace_event/trace_event.h"
|
||||
#include "util/png_utils.h"
|
||||
#include "util/shader_utils.h"
|
||||
#include "util/test_utils.h"
|
||||
|
||||
@@ -239,6 +240,12 @@ void ANGLEPerfTest::run()
|
||||
mStepsToRun = gStepsToRunOverride;
|
||||
}
|
||||
|
||||
// Check again for early exit.
|
||||
if (mSkipTest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Do another warmup run. Seems to consistently improve results.
|
||||
doRunLoop(kMaximumRunTimeSeconds);
|
||||
|
||||
@@ -647,6 +654,10 @@ void ANGLERenderTest::step()
|
||||
else
|
||||
{
|
||||
drawBenchmark();
|
||||
|
||||
// Saves a screenshot. The test will also exit early if we're taking screenshots.
|
||||
saveScreenshotIfEnabled();
|
||||
|
||||
// Swap is needed so that the GPU driver will occasionally flush its
|
||||
// internal command queue to the GPU. This is enabled for null back-end
|
||||
// devices because some back-ends (e.g. Vulkan) also accumulate internal
|
||||
@@ -747,6 +758,33 @@ std::vector<TraceEvent> &ANGLERenderTest::getTraceEventBuffer()
|
||||
return mTraceEventBuffer;
|
||||
}
|
||||
|
||||
void ANGLERenderTest::saveScreenshotIfEnabled()
|
||||
{
|
||||
if (gScreenShotDir == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream screenshotNameStr;
|
||||
screenshotNameStr << gScreenShotDir << GetPathSeparator() << "angle" << mBackend << "_"
|
||||
<< mStory << ".png";
|
||||
std::string screenshotName = screenshotNameStr.str();
|
||||
|
||||
// RGBA 4-byte data.
|
||||
std::vector<uint8_t> pixelData(mTestParams.windowWidth * mTestParams.windowHeight * 4);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glReadPixels(0, 0, mTestParams.windowWidth, mTestParams.windowHeight, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
pixelData.data());
|
||||
|
||||
angle::SavePNG(screenshotName.c_str(), "ANGLE Screenshot", mTestParams.windowWidth,
|
||||
mTestParams.windowHeight, pixelData);
|
||||
|
||||
// Early exit.
|
||||
abortTest();
|
||||
mSkipTest = true;
|
||||
}
|
||||
|
||||
namespace angle
|
||||
{
|
||||
double GetHostTimeSeconds()
|
||||
|
||||
@@ -69,6 +69,7 @@ class ANGLEPerfTest : public testing::Test, angle::NonCopyable
|
||||
virtual void startTest() {}
|
||||
// Called right before timer is stopped to let the test wait for asynchronous operations.
|
||||
virtual void finishTest() {}
|
||||
virtual void flush() {}
|
||||
|
||||
protected:
|
||||
void run();
|
||||
@@ -153,6 +154,8 @@ class ANGLERenderTest : public ANGLEPerfTest
|
||||
|
||||
bool mIsTimestampQueryAvailable;
|
||||
|
||||
void saveScreenshotIfEnabled();
|
||||
|
||||
private:
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
|
||||
namespace angle
|
||||
{
|
||||
bool gCalibration = false;
|
||||
int gStepsToRunOverride = -1;
|
||||
bool gEnableTrace = false;
|
||||
const char *gTraceFile = "ANGLETrace.json";
|
||||
bool gCalibration = false;
|
||||
int gStepsToRunOverride = -1;
|
||||
bool gEnableTrace = false;
|
||||
const char *gTraceFile = "ANGLETrace.json";
|
||||
const char *gScreenShotDir = nullptr;
|
||||
} // namespace angle
|
||||
|
||||
using namespace angle;
|
||||
@@ -37,7 +38,7 @@ void ANGLEProcessPerfTestArgs(int *argc, char **argv)
|
||||
}
|
||||
else if (strcmp("--trace-file", argv[argIndex]) == 0 && argIndex < *argc - 1)
|
||||
{
|
||||
gTraceFile = argv[argIndex];
|
||||
gTraceFile = argv[argIndex + 1];
|
||||
// Skip an additional argument.
|
||||
argIndex++;
|
||||
}
|
||||
@@ -55,6 +56,11 @@ void ANGLEProcessPerfTestArgs(int *argc, char **argv)
|
||||
// Skip an additional argument.
|
||||
argIndex++;
|
||||
}
|
||||
else if (strcmp("--screenshot-dir", argv[argIndex]) == 0 && argIndex < *argc - 1)
|
||||
{
|
||||
gScreenShotDir = argv[argIndex + 1];
|
||||
argIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
argv[argcOutCount++] = argv[argIndex];
|
||||
|
||||
@@ -18,6 +18,7 @@ extern bool gCalibration;
|
||||
extern int gStepsToRunOverride;
|
||||
extern bool gEnableTrace;
|
||||
extern const char *gTraceFile;
|
||||
extern const char *gScreenShotDir;
|
||||
|
||||
inline bool OneFrame()
|
||||
{
|
||||
|
||||
@@ -249,6 +249,19 @@ if (is_win && !angle_is_winuwp) {
|
||||
}
|
||||
}
|
||||
|
||||
config("angle_png_utils_config") {
|
||||
include_dirs = [ ".." ]
|
||||
}
|
||||
|
||||
angle_source_set("angle_png_utils") {
|
||||
deps = [ "$angle_libpng_dir" ]
|
||||
sources = [
|
||||
"png_utils.cpp",
|
||||
"png_utils.h",
|
||||
]
|
||||
public_configs = [ ":angle_png_utils_config" ]
|
||||
}
|
||||
|
||||
config("angle_test_util_config") {
|
||||
include_dirs = [ ".." ]
|
||||
}
|
||||
|
||||
116
util/png_utils.cpp
Normal file
116
util/png_utils.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
//
|
||||
// Copyright 2020 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.
|
||||
//
|
||||
// png_utils: Wrapper around libpng.
|
||||
//
|
||||
|
||||
#include "util/png_utils.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include <png.h>
|
||||
|
||||
namespace angle
|
||||
{
|
||||
namespace
|
||||
{
|
||||
class ScopedFILE
|
||||
{
|
||||
public:
|
||||
ScopedFILE(FILE *fp) : mFP(fp) {}
|
||||
~ScopedFILE() { close(); }
|
||||
|
||||
FILE *get() const { return mFP; }
|
||||
|
||||
void close()
|
||||
{
|
||||
if (mFP)
|
||||
{
|
||||
fclose(mFP);
|
||||
mFP = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FILE *mFP;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
bool SavePNG(const char *fileName,
|
||||
const char *title,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
const std::vector<uint8_t> &data)
|
||||
{
|
||||
ScopedFILE fp(fopen(fileName, "wb"));
|
||||
if (!fp.get())
|
||||
{
|
||||
fprintf(stderr, "Error opening '%s'.\n", fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_struct *writeStruct =
|
||||
png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
if (!writeStruct)
|
||||
{
|
||||
fprintf(stderr, "Error on png_create_write_struct.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
png_info *infoStruct = png_create_info_struct(writeStruct);
|
||||
if (!infoStruct)
|
||||
{
|
||||
fprintf(stderr, "Error on png_create_info_struct.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(writeStruct)))
|
||||
{
|
||||
fp.close();
|
||||
png_free_data(writeStruct, infoStruct, PNG_FREE_ALL, -1);
|
||||
png_destroy_write_struct(&writeStruct, &infoStruct);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_init_io(writeStruct, fp.get());
|
||||
|
||||
// Write header (8 bit colour depth)
|
||||
png_set_IHDR(writeStruct, infoStruct, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
|
||||
// Set title
|
||||
if (title != nullptr && strlen(title) > 0)
|
||||
{
|
||||
std::array<char, 50> mutableKey = {};
|
||||
strcpy(mutableKey.data(), "Title");
|
||||
std::array<char, 200> mutableText = {};
|
||||
strncpy(mutableText.data(), title, 199);
|
||||
|
||||
png_text titleText;
|
||||
titleText.compression = PNG_TEXT_COMPRESSION_NONE;
|
||||
titleText.key = mutableKey.data();
|
||||
titleText.text = mutableText.data();
|
||||
png_set_text(writeStruct, infoStruct, &titleText, 1);
|
||||
}
|
||||
|
||||
png_write_info(writeStruct, infoStruct);
|
||||
|
||||
// RGBA 4-byte stride.
|
||||
const uint32_t rowStride = width * 4;
|
||||
for (uint32_t row = 0; row < height; ++row)
|
||||
{
|
||||
uint32_t rowOffset = row * rowStride;
|
||||
png_write_row(writeStruct, &data[rowOffset]);
|
||||
}
|
||||
|
||||
png_write_end(writeStruct, infoStruct);
|
||||
|
||||
fp.close();
|
||||
png_free_data(writeStruct, infoStruct, PNG_FREE_ALL, -1);
|
||||
png_destroy_write_struct(&writeStruct, &infoStruct);
|
||||
return true;
|
||||
}
|
||||
} // namespace angle
|
||||
24
util/png_utils.h
Normal file
24
util/png_utils.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Copyright 2020 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.
|
||||
//
|
||||
// png_utils: Wrapper around libpng.
|
||||
//
|
||||
|
||||
#ifndef UTIL_PNG_UTILS_H_
|
||||
#define UTIL_PNG_UTILS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace angle
|
||||
{
|
||||
bool SavePNG(const char *fileName,
|
||||
const char *title,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
const std::vector<uint8_t> &data);
|
||||
} // namespace angle
|
||||
|
||||
#endif // UTIL_PNG_UTILS_H_
|
||||
Reference in New Issue
Block a user