[glfw] Add static render test creator

Press F1 to create a render test for the current view.

The test will be created at the base folder (current if nothing is
provided) + /NNNN (the next free entry).
This commit is contained in:
Thiago Marcos P. Santos
2019-12-02 16:20:50 +02:00
parent 6d425f8a7e
commit 71054c8b60
9 changed files with 256 additions and 8 deletions

View File

@@ -12,6 +12,8 @@ target_sources(mbgl-glfw
PRIVATE platform/glfw/glfw_renderer_frontend.cpp
PRIVATE platform/glfw/settings_json.hpp
PRIVATE platform/glfw/settings_json.cpp
PRIVATE platform/glfw/test_writer.hpp
PRIVATE platform/glfw/test_writer.cpp
)
target_include_directories(mbgl-glfw

View File

@@ -3,7 +3,7 @@
[
"mbgl-glfw",
"/src/workspace/next-linux-gcc8-release/bin/mbgl-glfw",
7205192
7323976
],
[
"mbgl-offline",

View File

@@ -3,7 +3,7 @@
[
"mbgl-glfw",
"/src/workspace/next-macos-xcode11-release/bin/mbgl-glfw",
5439932
5502420
],
[
"mbgl-offline",

View File

@@ -10,6 +10,7 @@ add_executable(
${MBGL_ROOT}/platform/glfw/glfw_gl_backend.cpp
${MBGL_ROOT}/platform/glfw/glfw_renderer_frontend.cpp
${MBGL_ROOT}/platform/glfw/settings_json.cpp
${MBGL_ROOT}/platform/glfw/test_writer.cpp
)
target_include_directories(
@@ -30,6 +31,8 @@ target_link_libraries(
PRIVATE
${GLFW_LIBRARIES}
Mapbox::Base::Extras::args
Mapbox::Base::Extras::filesystem
Mapbox::Base::Extras::rapidjson
Mapbox::Map
OpenGL::GL
mbgl-vendor-cheap-ruler-cpp

View File

@@ -2,6 +2,7 @@
#include "glfw_backend.hpp"
#include "glfw_renderer_frontend.hpp"
#include "ny_route.hpp"
#include "test_writer.hpp"
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/gfx/backend.hpp>
@@ -36,6 +37,7 @@
#include <cassert>
#include <cstdlib>
#include <iostream>
void glfwError(int error, const char *description) {
mbgl::Log::Error(mbgl::Event::OpenGL, "GLFW error (%i): %s", error, description);
@@ -124,8 +126,8 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
printf("- Press `E` to insert an example building extrusion layer\n");
printf("- Press `O` to toggle online connectivity\n");
printf("- Press `Z` to cycle through north orientations\n");
printf("- Prezz `X` to cycle through the viewport modes\n");
printf("- Press `I` to Delete existing database and re-initialize\n");
printf("- Press `X` to cycle through the viewport modes\n");
printf("- Press `I` to delete existing database and re-initialize\n");
printf("- Press `A` to cycle through Mapbox offices in the world + dateline monument\n");
printf("- Press `B` to cycle through the color, stencil, and depth buffer\n");
printf("- Press `D` to cycle through camera bounds: inside, crossing IDL at left, crossing IDL at right, and disabled\n");
@@ -138,10 +140,12 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
printf("- Press `K` to add a random custom runtime imagery annotation\n");
printf("- Press `L` to add a random line annotation\n");
printf("- Press `W` to pop the last-added annotation off\n");
printf("\n");
printf("- Press `P` to pause tile requests\n");
printf("- `Control` + mouse drag to rotate\n");
printf("- `Shift` + mouse drag to tilt\n");
printf("\n");
printf("- Hold `Control` + mouse drag to rotate\n");
printf("- Hold `Shift` + mouse drag to tilt\n");
printf("\n");
printf("- Press `F1` to generate a render test for the current view\n");
printf("\n");
printf("- Press `Tab` to cycle through the map debug options\n");
printf("- Press `Esc` to quit\n");
@@ -370,6 +374,20 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
: mbgl::style::VisibilityType::Visible);
}
} break;
case GLFW_KEY_F1: {
bool success = TestWriter()
.withInitialSize(mbgl::Size(view->width, view->height))
.withStyle(view->map->getStyle())
.withCameraOptions(view->map->getCameraOptions())
.write(view->testDirectory);
if (success) {
mbgl::Log::Info(mbgl::Event::General, "Render test created!");
} else {
mbgl::Log::Error(mbgl::Event::General,
"Fail to create render test! Base directory does not exist or permission denied.");
}
} break;
}
}

View File

@@ -29,6 +29,8 @@ public:
mbgl::gfx::RendererBackend& getRendererBackend();
void setTestDirectory(std::string dir) { testDirectory = std::move(dir); };
// Callback called when the user presses the key mapped to style change.
// The expected action is to set a new style, different to the current one.
void setChangeStyleCallback(std::function<void()> callback);
@@ -105,6 +107,8 @@ private:
GLFWRendererFrontend* rendererFrontend = nullptr;
std::unique_ptr<GLFWBackend> backend;
std::string testDirectory = ".";
bool fullscreen = false;
const bool benchmark = false;
bool tracking = false;

View File

@@ -43,7 +43,9 @@ int main(int argc, char *argv[]) {
args::Flag benchmarkFlag(argumentParser, "benchmark", "Toggle benchmark", {'b', "benchmark"});
args::Flag offlineFlag(argumentParser, "offline", "Toggle offline", {'o', "offline"});
args::ValueFlag<std::string> backendValue(argumentParser, "Backend", "Rendering backend", {"backend"});
args::ValueFlag<std::string> testDirValue(
argumentParser, "directory", "Root directory for test generation", {"testDir"});
args::ValueFlag<std::string> backendValue(argumentParser, "backend", "Rendering backend", {"backend"});
args::ValueFlag<std::string> styleValue(argumentParser, "URL", "Map stylesheet", {'s', "style"});
args::ValueFlag<std::string> cacheDBValue(argumentParser, "file", "Cache database file name", {'c', "cache"});
args::ValueFlag<double> lonValue(argumentParser, "degrees", "Longitude", {'x', "lon"});
@@ -128,6 +130,8 @@ int main(int argc, char *argv[]) {
.withPitch(settings.pitch));
map.setDebug(mbgl::MapDebugOptions(settings.debug));
if (testDirValue) view->setTestDirectory(args::get(testDirValue));
view->setOnlineStatusCallback([&settings, fileSource]() {
settings.online = !settings.online;
fileSource->setOnlineStatus(settings.online);

View File

@@ -0,0 +1,188 @@
#include "test_writer.hpp"
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <ghc/filesystem.hpp>
#include <cmath>
#include <fstream>
using Writer = rapidjson::PrettyWriter<rapidjson::StringBuffer>;
class TestOperation {
public:
virtual ~TestOperation() = default;
virtual void serialize(Writer& writer) const = 0;
};
class SetCamera final : public TestOperation {
public:
SetCamera(const mbgl::CameraOptions& camera_) : camera(camera_) {}
void serialize(Writer& writer) const override {
if (camera.zoom) {
writer.StartArray();
writer.String("setZoom");
writer.Double(*camera.zoom);
writer.EndArray();
}
if (camera.bearing && *camera.bearing != 0.) {
writer.StartArray();
writer.String("setBearing");
writer.Double(*camera.bearing);
writer.EndArray();
}
if (camera.pitch && *camera.pitch != 0.) {
writer.StartArray();
writer.String("setPitch");
writer.Int(std::round(*camera.pitch));
writer.EndArray();
}
writer.StartArray();
writer.String("setCenter");
writer.StartArray();
writer.Double(camera.center->longitude());
writer.Double(camera.center->latitude());
writer.EndArray();
writer.EndArray();
}
private:
mbgl::CameraOptions camera;
};
class SetStyle final : public TestOperation {
public:
SetStyle(const mbgl::style::Style& style) : url(style.getURL()) {}
void serialize(Writer& writer) const override {
writer.StartArray();
writer.String("setStyle");
writer.String(url);
writer.EndArray();
}
private:
std::string url;
};
class SetInitialSize final : public TestOperation {
public:
SetInitialSize(const mbgl::Size& size) : width(size.width), height(size.height) {}
void serialize(Writer& writer) const override {
writer.Key("width");
writer.Int(width);
writer.Key("height");
writer.Int(height);
}
private:
uint32_t width;
uint32_t height;
};
TestWriter::TestWriter() = default;
TestWriter::~TestWriter() = default;
TestWriter& TestWriter::withCameraOptions(const mbgl::CameraOptions& camera) {
operations.emplace_back(std::make_unique<SetCamera>(camera));
return *this;
}
TestWriter& TestWriter::withStyle(const mbgl::style::Style& style) {
operations.emplace_back(std::make_unique<SetStyle>(style));
return *this;
}
TestWriter& TestWriter::withInitialSize(const mbgl::Size& size) {
assert(initialSize == nullptr);
initialSize = std::make_unique<SetInitialSize>(size);
return *this;
}
bool TestWriter::write(const std::string& dir) const {
namespace fs = ghc::filesystem;
fs::path rootDir(dir);
if (!fs::exists(rootDir)) {
return false;
}
fs::path testDir;
for (int i = 0; i < 1000; ++i) {
std::string suffix = std::to_string(i);
suffix.insert(suffix.begin(), 3 - suffix.length(), '0');
testDir = rootDir / suffix;
if (!fs::exists(testDir)) {
break;
}
}
if (!fs::create_directory(testDir)) {
return false;
}
fs::path styleFile = testDir / "style.json";
std::ofstream out;
out.open(styleFile.string(), std::ios::out);
out << serialize();
return out.is_open() && out.good();
}
std::string TestWriter::serialize() const {
rapidjson::StringBuffer s;
Writer writer(s);
writer.StartObject();
writer.Key("version");
writer.Int(8);
writer.Key("metadata");
writer.StartObject();
writer.Key("test");
writer.StartObject();
writer.Key("operations");
writer.StartArray();
for (const auto& operation : operations) {
operation->serialize(writer);
}
writer.EndArray();
if (initialSize) {
initialSize->serialize(writer);
}
writer.EndObject();
writer.EndObject();
writer.Key("sources");
writer.StartObject();
writer.EndObject();
writer.Key("layers");
writer.StartArray();
writer.EndArray();
writer.EndObject();
return s.GetString();
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <mbgl/map/camera.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/util/size.hpp>
#include <memory>
#include <string>
#include <vector>
class TestOperation;
class TestWriter final {
public:
TestWriter();
~TestWriter();
TestWriter& withCameraOptions(const mbgl::CameraOptions&);
TestWriter& withStyle(const mbgl::style::Style&);
TestWriter& withInitialSize(const mbgl::Size&);
bool write(const std::string& dir) const;
private:
std::string serialize() const;
std::vector<std::unique_ptr<TestOperation>> operations;
std::unique_ptr<TestOperation> initialSize;
};