From 71054c8b609f02403bf28e91c4c4ab14f1468e5d Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Mon, 2 Dec 2019 16:20:50 +0200 Subject: [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). --- cmake/glfw.cmake | 2 + metrics/tests/binary-size/linux-gcc8/metrics.json | 2 +- .../tests/binary-size/macos-xcode11/metrics.json | 2 +- next/platform/glfw/CMakeLists.txt | 3 + platform/glfw/glfw_view.cpp | 28 ++- platform/glfw/glfw_view.hpp | 4 + platform/glfw/main.cpp | 6 +- platform/glfw/test_writer.cpp | 188 +++++++++++++++++++++ platform/glfw/test_writer.hpp | 29 ++++ 9 files changed, 256 insertions(+), 8 deletions(-) create mode 100644 platform/glfw/test_writer.cpp create mode 100644 platform/glfw/test_writer.hpp diff --git a/cmake/glfw.cmake b/cmake/glfw.cmake index 89a7768ad3..d595518954 100644 --- a/cmake/glfw.cmake +++ b/cmake/glfw.cmake @@ -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 diff --git a/metrics/tests/binary-size/linux-gcc8/metrics.json b/metrics/tests/binary-size/linux-gcc8/metrics.json index d8238e95f6..5b8e1f5bec 100644 --- a/metrics/tests/binary-size/linux-gcc8/metrics.json +++ b/metrics/tests/binary-size/linux-gcc8/metrics.json @@ -3,7 +3,7 @@ [ "mbgl-glfw", "/src/workspace/next-linux-gcc8-release/bin/mbgl-glfw", - 7205192 + 7323976 ], [ "mbgl-offline", diff --git a/metrics/tests/binary-size/macos-xcode11/metrics.json b/metrics/tests/binary-size/macos-xcode11/metrics.json index 9a4ffebd13..41886e8caf 100644 --- a/metrics/tests/binary-size/macos-xcode11/metrics.json +++ b/metrics/tests/binary-size/macos-xcode11/metrics.json @@ -3,7 +3,7 @@ [ "mbgl-glfw", "/src/workspace/next-macos-xcode11-release/bin/mbgl-glfw", - 5439932 + 5502420 ], [ "mbgl-offline", diff --git a/next/platform/glfw/CMakeLists.txt b/next/platform/glfw/CMakeLists.txt index e4c0920a44..b0263362a7 100644 --- a/next/platform/glfw/CMakeLists.txt +++ b/next/platform/glfw/CMakeLists.txt @@ -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 diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index 74dda734c0..3d10f2c654 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -2,6 +2,7 @@ #include "glfw_backend.hpp" #include "glfw_renderer_frontend.hpp" #include "ny_route.hpp" +#include "test_writer.hpp" #include #include @@ -36,6 +37,7 @@ #include #include +#include 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; } } diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp index 9233bddfb9..e9867f14da 100644 --- a/platform/glfw/glfw_view.hpp +++ b/platform/glfw/glfw_view.hpp @@ -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 callback); @@ -105,6 +107,8 @@ private: GLFWRendererFrontend* rendererFrontend = nullptr; std::unique_ptr backend; + std::string testDirectory = "."; + bool fullscreen = false; const bool benchmark = false; bool tracking = false; diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp index 3c1e50e196..8f134804f0 100644 --- a/platform/glfw/main.cpp +++ b/platform/glfw/main.cpp @@ -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 backendValue(argumentParser, "Backend", "Rendering backend", {"backend"}); + args::ValueFlag testDirValue( + argumentParser, "directory", "Root directory for test generation", {"testDir"}); + args::ValueFlag backendValue(argumentParser, "backend", "Rendering backend", {"backend"}); args::ValueFlag styleValue(argumentParser, "URL", "Map stylesheet", {'s', "style"}); args::ValueFlag cacheDBValue(argumentParser, "file", "Cache database file name", {'c', "cache"}); args::ValueFlag 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); diff --git a/platform/glfw/test_writer.cpp b/platform/glfw/test_writer.cpp new file mode 100644 index 0000000000..d125170aed --- /dev/null +++ b/platform/glfw/test_writer.cpp @@ -0,0 +1,188 @@ +#include "test_writer.hpp" + +#include +#include +#include +#include + +#include +#include + +using Writer = rapidjson::PrettyWriter; + +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(camera)); + + return *this; +} + +TestWriter& TestWriter::withStyle(const mbgl::style::Style& style) { + operations.emplace_back(std::make_unique(style)); + + return *this; +} + +TestWriter& TestWriter::withInitialSize(const mbgl::Size& size) { + assert(initialSize == nullptr); + initialSize = std::make_unique(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(); +} diff --git a/platform/glfw/test_writer.hpp b/platform/glfw/test_writer.hpp new file mode 100644 index 0000000000..8e41e3e49a --- /dev/null +++ b/platform/glfw/test_writer.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +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> operations; + std::unique_ptr initialSize; +}; -- cgit v1.2.1