Adds ability to toggle multi-frame rendering. (#49)

This commit is contained in:
Erik Abair 2022-01-24 07:51:48 -08:00 committed by GitHub
parent 7643b86554
commit c844f7a67f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 126 additions and 62 deletions

View File

@ -24,6 +24,7 @@ DPAD:
* A - Enter a submenu or test. Inside of a test, re-run the test.
* B - Go up one menu or leave a test. If pressed on the root menu, exit the application.
* X - Run all tests for the current suite.
* Y - Toggle saving of results and multi-frame rendering.
* Start - Enter a submenu or test.
* Back - Go up one menu or leave a test. If pressed on the root menu, exit the application.
* Black - Exit the application.

View File

@ -82,7 +82,7 @@ int main() {
std::vector<std::shared_ptr<TestSuite>> test_suites;
register_suites(host, test_suites, test_output_directory);
TestDriver driver(test_suites, kFramebufferWidth, kFramebufferHeight);
TestDriver driver(host, test_suites, kFramebufferWidth, kFramebufferHeight);
driver.Run();
debugPrint("Results written to %s\n\nRebooting in 4 seconds...\n", test_output_directory.c_str());

View File

@ -11,6 +11,9 @@ static constexpr uint32_t kAutoTestAllTimeoutMilliseconds = 3000;
static constexpr uint32_t kNumItemsPerPage = 12;
static constexpr uint32_t kNumItemsPerHalfPage = kNumItemsPerPage >> 1;
uint32_t MenuItem::menu_background_color_ = 0xFF3E003E;
bool MenuItemTest::one_shot_mode_ = true;
void MenuItem::PrepareDraw(uint32_t background_color) const {
pb_wait_for_vbl();
pb_target_back_buffer();
@ -31,13 +34,13 @@ void MenuItem::Swap() {
}
}
void MenuItem::Draw() const {
void MenuItem::Draw() {
if (active_submenu) {
active_submenu->Draw();
return;
}
PrepareDraw();
PrepareDraw(menu_background_color_);
const char *cursor_prefix = "> ";
const char *normal_prefix = " ";
@ -176,17 +179,27 @@ void MenuItem::CursorDownAndActivate() {
Activate();
}
void MenuItem::SetBackgroundColor(uint32_t background_color) { menu_background_color_ = background_color; }
MenuItemCallable::MenuItemCallable(std::function<void()> callback, std::string name, uint32_t width, uint32_t height)
: MenuItem(std::move(name), width, height), on_activate(std::move(callback)) {}
void MenuItemCallable::Draw() const {}
void MenuItemCallable::Draw() {}
void MenuItemCallable::Activate() { on_activate(); }
MenuItemTest::MenuItemTest(std::shared_ptr<TestSuite> suite, std::string name, uint32_t width, uint32_t height)
: MenuItem(std::move(name), width, height), suite(std::move(suite)) {}
void MenuItemTest::Draw() const {}
void MenuItemTest::Draw() {
if (one_shot_mode_ && has_run_once_) {
return;
}
suite->Run(name);
suite->SetSavingAllowed(false);
has_run_once_ = true;
}
void MenuItemTest::OnEnter() {
// Blank the screen.
@ -195,8 +208,13 @@ void MenuItemTest::OnEnter() {
Swap();
suite->Initialize();
suite->Run(name);
suite->SetSavingAllowed(true);
has_run_once_ = false;
}
bool MenuItemTest::Deactivate() {
suite->Deinitialize();
return MenuItem::Deactivate();
}
void MenuItemTest::CursorUp() { parent->CursorUpAndActivate(); }
@ -241,7 +259,7 @@ void MenuItemRoot::ActivateCurrentSuite() {
MenuItem::ActivateCurrentSuite();
}
void MenuItemRoot::Draw() const {
void MenuItemRoot::Draw() {
#ifndef DISABLE_AUTORUN
if (!timer_cancelled) {
auto now = std::chrono::high_resolution_clock::now();

View File

@ -14,10 +14,12 @@ struct MenuItem {
public:
MenuItem(std::string name, uint32_t width, uint32_t height) : width(width), height(height), name(std::move(name)) {}
static void SetBackgroundColor(uint32_t background_color);
// Whether or not this menu item becomes the active drawable when activated.
virtual bool IsEnterable() const { return !submenu.empty(); }
virtual void Draw() const;
virtual void Draw();
// Invoked when this MenuItem becomes the active drawable.
virtual void OnEnter();
@ -38,7 +40,7 @@ struct MenuItem {
void CursorDownAndActivate();
protected:
void PrepareDraw(uint32_t background_color = 0xFF3E003E) const;
void PrepareDraw(uint32_t background_color) const;
static void Swap();
public:
@ -46,6 +48,8 @@ struct MenuItem {
uint32_t height;
std::string name;
static uint32_t menu_background_color_;
uint32_t cursor_position{0};
std::vector<std::shared_ptr<MenuItem>> submenu{};
std::shared_ptr<MenuItem> active_submenu{};
@ -55,7 +59,7 @@ struct MenuItem {
struct MenuItemCallable : public MenuItem {
MenuItemCallable(std::function<void()> on_activate, std::string name, uint32_t width, uint32_t height);
void Draw() const override;
void Draw() override;
void Activate() override;
void ActivateCurrentSuite() override {}
@ -63,19 +67,26 @@ struct MenuItemCallable : public MenuItem {
};
struct MenuItemTest : public MenuItem {
static bool one_shot_mode_;
MenuItemTest(std::shared_ptr<TestSuite> suite, std::string name, uint32_t width, uint32_t height);
static void SetOneShotMode(bool val) { one_shot_mode_ = val; }
bool IsEnterable() const override { return true; }
void Draw() const override;
void Draw() override;
void OnEnter() override;
void Activate() override { OnEnter(); }
bool Deactivate() override;
void ActivateCurrentSuite() override {}
void CursorUp() override;
void CursorDown() override;
void CursorLeft() override {}
void CursorRight() override {}
std::shared_ptr<TestSuite> suite;
bool has_run_once_{false};
};
struct MenuItemSuite : public MenuItem {
@ -89,7 +100,7 @@ struct MenuItemRoot : public MenuItem {
explicit MenuItemRoot(const std::vector<std::shared_ptr<TestSuite>>& suites, std::function<void()> on_run_all,
std::function<void()> on_exit, uint32_t width, uint32_t height);
void Draw() const override;
void Draw() override;
void Activate() override;
void ActivateCurrentSuite() override;
bool Deactivate() override;

View File

@ -6,9 +6,12 @@
#include "menu_item.h"
TestDriver::TestDriver(const std::vector<std::shared_ptr<TestSuite>> &test_suites, uint32_t framebuffer_width,
uint32_t framebuffer_height)
: test_suites_(test_suites), framebuffer_width_(framebuffer_width), framebuffer_height_(framebuffer_height) {
TestDriver::TestDriver(TestHost &host, const std::vector<std::shared_ptr<TestSuite>> &test_suites,
uint32_t framebuffer_width, uint32_t framebuffer_height)
: test_host_(host),
test_suites_(test_suites),
framebuffer_width_(framebuffer_width),
framebuffer_height_(framebuffer_height) {
auto on_run_all = [this]() { RunAllTestsNonInteractive(); };
auto on_exit = [this]() { running_ = false; };
menu_ = std::make_shared<MenuItemRoot>(test_suites, on_run_all, on_exit, framebuffer_width, framebuffer_height);
@ -46,7 +49,14 @@ void TestDriver::Run() {
}
}
if (!test_host_.GetSaveResults()) {
menu_->SetBackgroundColor(0xFF3E1E1E);
} else {
menu_->SetBackgroundColor(0xFF1E1E1E);
}
menu_->Draw();
Sleep(10);
}
}
@ -143,6 +153,10 @@ void TestDriver::OnControllerButtonEvent(const SDL_ControllerButtonEvent &event)
OnX();
break;
case SDL_CONTROLLER_BUTTON_Y:
OnY();
break;
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
OnBlack();
break;
@ -167,6 +181,12 @@ void TestDriver::OnB() { menu_->Deactivate(); }
void TestDriver::OnX() { menu_->ActivateCurrentSuite(); }
void TestDriver::OnY() {
bool save_results = !test_host_.GetSaveResults();
test_host_.SetSaveResults(save_results);
MenuItemTest::SetOneShotMode(save_results);
}
void TestDriver::OnUp() { menu_->CursorUp(); }
void TestDriver::OnDown() { menu_->CursorDown(); }

View File

@ -8,6 +8,7 @@
#include <memory>
#include <vector>
#include "test_host.h"
#include "tests/test_suite.h"
constexpr uint32_t kMaxGamepads = 4;
@ -16,7 +17,7 @@ struct MenuItem;
class TestDriver {
public:
TestDriver(const std::vector<std::shared_ptr<TestSuite>> &test_suites, uint32_t framebuffer_width,
TestDriver(TestHost &host, const std::vector<std::shared_ptr<TestSuite>> &test_suites, uint32_t framebuffer_width,
uint32_t framebuffer_height);
~TestDriver();
@ -40,15 +41,20 @@ class TestDriver {
void OnA();
void OnB();
void OnX();
void OnY();
private:
bool running_{true};
volatile bool running_{true};
// Whether tests should render once and stop (true) or continually render frames (false).
bool one_shot_tests_{true};
const std::vector<std::shared_ptr<TestSuite>> &test_suites_;
SDL_GameController *gamepads_[kMaxGamepads]{nullptr};
uint32_t framebuffer_width_;
uint32_t framebuffer_height_;
TestHost &test_host_;
std::shared_ptr<MenuItem> menu_;
};

View File

@ -649,31 +649,28 @@ int TestHost::SetTexture(SDL_Surface *gradient_surface) {
return 0;
}
void TestHost::FinishDraw() const {
void TestHost::FinishDraw(bool allow_saving, const std::string &output_directory, const std::string &name,
const std::string &z_buffer_name) {
bool perform_save = allow_saving && save_results_;
if (!perform_save) {
pb_printat(0, 55, (char *)"ns");
pb_draw_text_screen();
}
while (pb_busy()) {
/* Wait for completion... */
}
/* Swap buffers (if we can) */
while (pb_finished()) {
/* Not ready to swap yet */
}
}
if (perform_save) {
// TODO: See why waiting for tiles to be non-busy results in the screen not updating anymore.
// In theory this should wait for all tiles to be rendered before capturing.
pb_wait_for_vbl();
void TestHost::FinishDrawAndSave(const std::string &output_directory, const std::string &name,
const std::string &z_buffer_name) {
while (pb_busy()) {
/* Wait for completion... */
}
SaveBackBuffer(output_directory, name);
// TODO: See why waiting for tiles to be non-busy results in the screen not updating anymore.
// In theory this should wait for all tiles to be rendered before capturing.
pb_wait_for_vbl();
SaveBackBuffer(output_directory, name);
if (!z_buffer_name.empty()) {
SaveZBuffer(output_directory, z_buffer_name);
if (!z_buffer_name.empty()) {
SaveZBuffer(output_directory, z_buffer_name);
}
}
/* Swap buffers (if we can) */

View File

@ -93,9 +93,8 @@ class TestHost {
void DrawInlineElements32(const std::vector<uint32_t> &indices, uint32_t enabled_vertex_fields = 0xFFFFFFFF,
DrawPrimitive primitive = PRIMITIVE_TRIANGLES);
void FinishDraw() const;
void FinishDrawAndSave(const std::string &output_directory, const std::string &name,
const std::string &z_buffer_name = "");
void FinishDraw(bool allow_saving, const std::string &output_directory, const std::string &name,
const std::string &z_buffer_name = "");
void SetShaderProgram(std::shared_ptr<ShaderProgram> program);
std::shared_ptr<ShaderProgram> GetShaderProgram() const { return shader_program_; }
@ -122,6 +121,9 @@ class TestHost {
static std::string GetPrimitiveName(DrawPrimitive primitive);
bool GetSaveResults() const { return save_results_; }
void SetSaveResults(bool enable = true) { save_results_ = enable; }
private:
void SetVertexBufferAttributes(uint32_t enabled_fields);
void SetupControl0() const;
@ -156,6 +158,8 @@ class TestHost {
FixedFunctionMatrixSetting fixed_function_matrix_mode_{MATRIX_MODE_DEFAULT_NXDK};
MATRIX fixed_function_model_view_matrix_{};
MATRIX fixed_function_projection_matrix_{};
bool save_results_{true};
};
#endif // NXDK_PGRAPH_TESTS_TEST_HOST_H

View File

@ -72,7 +72,7 @@ void DepthFormatTests::Test(const DepthFormat &format, bool compress_z, uint32_t
std::string name = MakeTestName(format, compress_z, depth_cutoff);
std::string z_name = name + "_ZB";
host_.FinishDrawAndSave(output_dir_, name, z_name);
host_.FinishDraw(allow_saving_, output_dir_, name, z_name);
}
void DepthFormatTests::CreateGeometry(const DepthFormat &format) {

View File

@ -192,7 +192,7 @@ void FogTests::Test(FogTests::FogMode fog_mode, FogTests::FogGenMode gen_mode, u
pb_print("%s\n", name.c_str());
pb_draw_text_screen();
host_.FinishDrawAndSave(output_dir_, name);
host_.FinishDraw(allow_saving_, output_dir_, name);
}
std::string FogTests::MakeTestName(FogTests::FogMode fog_mode, FogTests::FogGenMode gen_mode, uint32_t fog_alpha) {

View File

@ -127,7 +127,7 @@ void FrontFaceTests::Test(uint32_t front_face, uint32_t cull_face) {
pb_draw_text_screen();
std::string name = MakeTestName(front_face, cull_face);
host_.FinishDrawAndSave(output_dir_, name);
host_.FinishDraw(allow_saving_, output_dir_, name);
}
std::string FrontFaceTests::MakeTestName(uint32_t front_face, uint32_t cull_face) {

View File

@ -221,7 +221,7 @@ void ImageBlitTests::Test(const BlitTest& test) {
pb_draw_text_screen();
std::string name = MakeTestName(test);
host_.FinishDrawAndSave(output_dir_, name);
host_.FinishDraw(allow_saving_, output_dir_, name);
}
std::string ImageBlitTests::MakeTestName(const BlitTest& test) {

View File

@ -199,7 +199,7 @@ void LightingNormalTests::Test(bool set_normal, const float* normal, DrawMode dr
pb_draw_text_screen();
std::string name = MakeTestName(set_normal, normal, draw_mode);
host_.FinishDrawAndSave(output_dir_, name);
host_.FinishDraw(allow_saving_, output_dir_, name);
}
std::string LightingNormalTests::MakeTestName(bool set_normal, const float* normal, DrawMode draw_mode) {

View File

@ -181,7 +181,7 @@ void MaterialAlphaTests::Test(uint32_t diffuse_source, float material_alpha) {
pb_draw_text_screen();
std::string name = MakeTestName(diffuse_source, material_alpha);
host_.FinishDrawAndSave(output_dir_, name);
host_.FinishDraw(allow_saving_, output_dir_, name);
}
std::string MaterialAlphaTests::MakeTestName(uint32_t diffuse_source, float material_alpha) {

View File

@ -286,7 +286,7 @@ void MaterialColorSourceTests::Test(SourceMode source_mode) {
pb_printat(9, 36, (char*)"Emissive");
pb_draw_text_screen();
host_.FinishDrawAndSave(output_dir_, name);
host_.FinishDraw(allow_saving_, output_dir_, name);
}
std::string MaterialColorSourceTests::MakeTestName(SourceMode source_mode) {

View File

@ -273,5 +273,5 @@ void MaterialColorTests::Test(TestConfig config) {
pb_printat(15, 17, (char*)"Towards light");
pb_draw_text_screen();
host_.FinishDrawAndSave(output_dir_, config.name);
host_.FinishDraw(allow_saving_, output_dir_, config.name);
}

View File

@ -219,7 +219,7 @@ void SetVertexDataTests::Test(SetFunction func, const Color& diffuse, bool satur
pb_draw_text_screen();
host_.FinishDrawAndSave(output_dir_, name);
host_.FinishDraw(allow_saving_, output_dir_, name);
}
std::string SetVertexDataTests::MakeTestName(SetFunction func, bool saturate_sign) {

View File

@ -5,10 +5,10 @@
#include "test_host.h"
#include "texture_format.h"
TestSuite::TestSuite(TestHost& host, std::string output_dir, std::string test_name)
: host_(host), output_dir_(std::move(output_dir)), test_name_(std::move(test_name)) {
TestSuite::TestSuite(TestHost& host, std::string output_dir, std::string suite_name)
: host_(host), output_dir_(std::move(output_dir)), suite_name_(std::move(suite_name)) {
output_dir_ += "\\";
output_dir_ += test_name_;
output_dir_ += suite_name_;
std::replace(output_dir_.begin(), output_dir_.end(), ' ', '_');
}

View File

@ -9,9 +9,9 @@ class TestHost;
class TestSuite {
public:
TestSuite(TestHost &host, std::string output_dir, std::string test_name);
TestSuite(TestHost &host, std::string output_dir, std::string suite_name);
const std::string &Name() const { return test_name_; };
const std::string &Name() const { return suite_name_; };
virtual void Initialize();
virtual void Deinitialize() {}
@ -21,13 +21,20 @@ class TestSuite {
void RunAll();
void SetSavingAllowed(bool enable = true) { allow_saving_ = enable; }
protected:
void SetDefaultTextureFormat() const;
protected:
TestHost &host_;
std::string output_dir_;
std::string test_name_;
std::string suite_name_;
// Flag to forcibly disallow saving of output (e.g., when in multiframe test mode for debugging).
bool allow_saving_{true};
// Map of `test_name` to `void test()`
std::map<std::string, std::function<void()>> tests_{};
};

View File

@ -41,6 +41,7 @@ void TextureFormatTests::CreateGeometry() {
void TextureFormatTests::Test(const TextureFormatInfo &texture_format) {
host_.SetTextureFormat(texture_format);
std::string test_name = MakeTestName(texture_format);
SDL_Surface *gradient_surface;
int update_texture_result =
@ -51,7 +52,7 @@ void TextureFormatTests::Test(const TextureFormatInfo &texture_format) {
} else {
pb_print("FAILED TO GENERATE SDL SURFACE - TEST IS INVALID: %d\n", update_texture_result);
pb_draw_text_screen();
host_.FinishDraw();
host_.FinishDraw(false, "", "");
return;
}
@ -69,8 +70,7 @@ void TextureFormatTests::Test(const TextureFormatInfo &texture_format) {
pb_print("ERR: %d\n", update_texture_result);
pb_draw_text_screen();
std::string test_name = MakeTestName(texture_format);
host_.FinishDrawAndSave(output_dir_, test_name);
host_.FinishDraw(allow_saving_, output_dir_, test_name);
}
std::string TextureFormatTests::MakeTestName(const TextureFormatInfo &texture_format) {

View File

@ -373,7 +373,7 @@ void ThreeDPrimitiveTests::Test(TestHost::DrawPrimitive primitive, DrawMode draw
pb_print("%s\n", name.c_str());
pb_draw_text_screen();
host_.FinishDrawAndSave(output_dir_, name);
host_.FinishDraw(allow_saving_, output_dir_, name);
}
std::string ThreeDPrimitiveTests::MakeTestName(TestHost::DrawPrimitive primitive,

View File

@ -88,7 +88,7 @@ void TwoDLineTests::Test(const TestCase& test) {
pb_draw_text_screen();
std::string name = MakeTestName(test, true);
host_.FinishDrawAndSave(output_dir_, name);
host_.FinishDraw(allow_saving_, output_dir_, name);
}
std::string TwoDLineTests::MakeTestName(const TestCase& test, bool ReturnShortName) {

View File

@ -162,7 +162,7 @@ void WParamTests::TestWGaps() {
pb_printat(15, 39, (char*)"inf,inf");
pb_draw_text_screen();
host_.FinishDrawAndSave(output_dir_, kTestWGaps);
host_.FinishDraw(allow_saving_, output_dir_, kTestWGaps);
}
void WParamTests::CreateGeometryPositiveWTriangleStrip() {
@ -200,7 +200,7 @@ void WParamTests::TestPositiveWTriangleStrip() {
host_.SetVertexBuffer(triangle_strip_);
host_.PrepareDraw();
host_.DrawArrays(TestHost::POSITION | TestHost::DIFFUSE, TestHost::PRIMITIVE_TRIANGLE_STRIP);
host_.FinishDrawAndSave(output_dir_, kTestWPositiveTriangleStrip);
host_.FinishDraw(allow_saving_, output_dir_, kTestWPositiveTriangleStrip);
}
void WParamTests::CreateGeometryNegativeWTriangleStrip() {
@ -259,5 +259,5 @@ void WParamTests::TestNegativeWTriangleStrip() {
p = pb_push1(p, NV097_SET_BACK_POLYGON_MODE, NV097_SET_FRONT_POLYGON_MODE_V_FILL);
pb_end(p);
host_.FinishDrawAndSave(output_dir_, kTestWNegativeTriangleStrip);
host_.FinishDraw(allow_saving_, output_dir_, kTestWNegativeTriangleStrip);
}