nxdk_pgraph_tests/src/tests/test_suite.cpp

331 lines
12 KiB
C++

#include "test_suite.h"
#include <fstream>
#include "configure.h"
#include "debug_output.h"
#include "logger.h"
#include "pbkit_ext.h"
#include "shaders/pixel_shader_program.h"
#include "test_host.h"
#include "texture_format.h"
#include "xbox_math_matrix.h"
#include "xbox_math_types.h"
using namespace XboxMath;
#define SET_MASK(mask, val) (((val) << (__builtin_ffs(mask) - 1)) & (mask))
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)), pgraph_diff_(false) {
output_dir_ += "\\";
output_dir_ += suite_name_;
std::replace(output_dir_.begin(), output_dir_.end(), ' ', '_');
}
std::vector<std::string> TestSuite::TestNames() const {
std::vector<std::string> ret;
ret.reserve(tests_.size());
for (auto& kv : tests_) {
ret.push_back(kv.first);
}
return std::move(ret);
}
void TestSuite::DisableTests(const std::vector<std::string>& tests_to_skip) {
for (auto& name : tests_to_skip) {
tests_.erase(name);
}
}
void TestSuite::Run(const std::string& test_name) {
auto it = tests_.find(test_name);
if (it == tests_.end()) {
ASSERT(!"Invalid test name");
}
SetupTest();
auto start_time = LogTestStart(test_name);
it->second();
LogTestEnd(test_name, start_time);
TearDownTest();
}
void TestSuite::RunAll() {
auto names = TestNames();
for (const auto& test_name : names) {
if (suspected_crashes_.find(test_name) != suspected_crashes_.end()) {
switch (suspected_crash_handling_mode_) {
case SuspectedCrashHandling::RUN_ALL:
break;
case SuspectedCrashHandling::SKIP_ALL:
continue;
case SuspectedCrashHandling::ASK:
// TODO: IMPLEMENT ASK MODE FOR CRASH HANDLING
ASSERT(!"TODO: IMPLEMENT ME");
break;
}
}
Run(test_name);
}
}
void TestSuite::SetDefaultTextureFormat() const {
const TextureFormatInfo& texture_format = GetTextureFormatInfo(NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X8R8G8B8);
host_.SetTextureFormat(texture_format, 0);
host_.SetDefaultTextureParams(0);
host_.SetTextureFormat(texture_format, 1);
host_.SetDefaultTextureParams(1);
host_.SetTextureFormat(texture_format, 2);
host_.SetDefaultTextureParams(2);
host_.SetTextureFormat(texture_format, 3);
host_.SetDefaultTextureParams(3);
}
void TestSuite::Initialize() {
const uint32_t kFramebufferPitch = host_.GetFramebufferWidth() * 4;
host_.SetSurfaceFormat(TestHost::SCF_A8R8G8B8, TestHost::SZF_Z16, host_.GetFramebufferWidth(),
host_.GetFramebufferHeight());
{
auto p = pb_begin();
p = pb_push4f(p, NV097_SET_EYE_POSITION, 0.0f, 0.0f, 0.0f, 1.0f);
p = pb_push1(p, NV097_SET_ZMIN_MAX_CONTROL,
NV097_SET_ZMIN_MAX_CONTROL_CULL_NEAR_FAR_EN_TRUE | NV097_SET_ZMIN_MAX_CONTROL_ZCLAMP_EN_CULL |
NV097_SET_ZMIN_MAX_CONTROL_CULL_IGNORE_W_FALSE);
p = pb_push1(p, NV097_SET_SURFACE_PITCH,
SET_MASK(NV097_SET_SURFACE_PITCH_COLOR, kFramebufferPitch) |
SET_MASK(NV097_SET_SURFACE_PITCH_ZETA, kFramebufferPitch));
p = pb_push1(p, NV097_SET_SURFACE_CLIP_HORIZONTAL, host_.GetFramebufferWidth() << 16);
p = pb_push1(p, NV097_SET_SURFACE_CLIP_VERTICAL, host_.GetFramebufferHeight() << 16);
p = pb_push1(p, NV097_SET_LIGHTING_ENABLE, false);
p = pb_push1(p, NV097_SET_SPECULAR_ENABLE, false);
p = pb_push1(p, NV097_SET_LIGHT_CONTROL, 0x20001);
p = pb_push1(p, NV097_SET_LIGHT_ENABLE_MASK, NV097_SET_LIGHT_ENABLE_MASK_LIGHT0_OFF);
p = pb_push1(p, NV097_SET_COLOR_MATERIAL, NV097_SET_COLOR_MATERIAL_ALL_FROM_MATERIAL);
p = pb_push3(p, NV097_SET_SCENE_AMBIENT_COLOR, 0x0, 0x0, 0x0);
p = pb_push3(p, NV097_SET_MATERIAL_EMISSION, 0x0, 0x0, 0x0);
p = pb_push1f(p, NV097_SET_MATERIAL_ALPHA, 1.0f);
p = pb_push1f(p, NV097_SET_BACK_MATERIAL_ALPHA, 0.f);
p = pb_push1(p, NV097_SET_LIGHT_TWO_SIDE_ENABLE, false);
p = pb_push1(p, NV097_SET_FRONT_POLYGON_MODE, NV097_SET_FRONT_POLYGON_MODE_V_FILL);
p = pb_push1(p, NV097_SET_BACK_POLYGON_MODE, NV097_SET_FRONT_POLYGON_MODE_V_FILL);
p = pb_push1(p, NV097_SET_VERTEX_DATA4UB + (4 * NV2A_VERTEX_ATTR_SPECULAR), 0);
p = pb_push1(p, NV097_SET_VERTEX_DATA4UB + (4 * NV2A_VERTEX_ATTR_BACK_DIFFUSE), 0xFFFFFFFF);
p = pb_push1(p, NV097_SET_VERTEX_DATA4UB + (4 * NV2A_VERTEX_ATTR_BACK_SPECULAR), 0);
p = pb_push1(p, NV097_SET_POINT_PARAMS_ENABLE, false);
p = pb_push1(p, NV097_SET_POINT_SMOOTH_ENABLE, false);
p = pb_push1(p, NV097_SET_POINT_SIZE, 8);
p = pb_push1(p, NV097_SET_DOT_RGBMAPPING, 0);
p = pb_push1(p, NV097_SET_SHADE_MODEL, NV097_SET_SHADE_MODEL_SMOOTH);
p = pb_push1(p, NV097_SET_FLAT_SHADE_PROVOKING_VERTEX, NV097_SET_FLAT_SHADE_PROVOKING_VERTEX_LAST);
pb_end(p);
}
host_.SetWindowClipExclusive(false);
// Note, setting the first clip region will cause the hardware to also set all subsequent regions.
host_.SetWindowClip(host_.GetFramebufferWidth(), host_.GetFramebufferHeight());
host_.SetBlend();
host_.ClearInputColorCombiners();
host_.ClearInputAlphaCombiners();
host_.ClearOutputColorCombiners();
host_.ClearOutputAlphaCombiners();
host_.SetCombinerControl(1);
host_.SetInputColorCombiner(0, TestHost::SRC_DIFFUSE, false, TestHost::MAP_UNSIGNED_IDENTITY, TestHost::SRC_ZERO,
false, TestHost::MAP_UNSIGNED_INVERT);
host_.SetInputAlphaCombiner(0, TestHost::SRC_DIFFUSE, true, TestHost::MAP_UNSIGNED_IDENTITY, TestHost::SRC_ZERO,
false, TestHost::MAP_UNSIGNED_INVERT);
host_.SetOutputColorCombiner(0, TestHost::DST_DISCARD, TestHost::DST_DISCARD, TestHost::DST_R0);
host_.SetOutputAlphaCombiner(0, TestHost::DST_DISCARD, TestHost::DST_DISCARD, TestHost::DST_R0);
host_.SetFinalCombiner0(TestHost::SRC_ZERO, false, false, TestHost::SRC_ZERO, false, false, TestHost::SRC_ZERO, false,
false, TestHost::SRC_R0);
host_.SetFinalCombiner1(TestHost::SRC_ZERO, false, false, TestHost::SRC_ZERO, false, false, TestHost::SRC_R0, true,
false, false, false, true);
host_.SetShaderStageProgram(TestHost::STAGE_NONE, TestHost::STAGE_NONE, TestHost::STAGE_NONE, TestHost::STAGE_NONE);
while (pb_busy()) {
/* Wait for completion... */
}
matrix4_t identity_matrix;
MatrixSetIdentity(identity_matrix);
for (auto i = 0; i < 4; ++i) {
auto& stage = host_.GetTextureStage(i);
stage.SetUWrap(TextureStage::WRAP_CLAMP_TO_EDGE, false);
stage.SetVWrap(TextureStage::WRAP_CLAMP_TO_EDGE, false);
stage.SetPWrap(TextureStage::WRAP_CLAMP_TO_EDGE, false);
stage.SetQWrap(false);
stage.SetEnabled(false);
stage.SetCubemapEnable(false);
stage.SetFilter();
stage.SetAlphaKillEnable(false);
stage.SetColorKeyMode(TextureStage::CKM_DISABLE);
stage.SetLODClamp(0, 4095);
stage.SetTextureMatrixEnable(false);
stage.SetTextureMatrix(identity_matrix);
stage.SetTexgenS(TextureStage::TG_DISABLE);
stage.SetTexgenT(TextureStage::TG_DISABLE);
stage.SetTexgenR(TextureStage::TG_DISABLE);
stage.SetTexgenQ(TextureStage::TG_DISABLE);
}
// TODO: Set up with TextureStage instances in host_.
{
auto p = pb_begin();
uint32_t address = NV097_SET_TEXTURE_ADDRESS;
uint32_t control = NV097_SET_TEXTURE_CONTROL0;
uint32_t filter = NV097_SET_TEXTURE_FILTER;
p = pb_push1(p, address, 0x10101);
p = pb_push1(p, control, 0x3ffc0);
p = pb_push1(p, filter, 0x1012000);
address += 0x40;
control += 0x40;
filter += 0x40;
p = pb_push1(p, address, 0x10101);
p = pb_push1(p, control, 0x3ffc0);
p = pb_push1(p, filter, 0x1012000);
address += 0x40;
control += 0x40;
filter += 0x40;
p = pb_push1(p, address, 0x10101);
p = pb_push1(p, control, 0x3ffc0);
p = pb_push1(p, filter, 0x1012000);
address += 0x40;
control += 0x40;
filter += 0x40;
p = pb_push1(p, address, 0x10101);
p = pb_push1(p, control, 0x3ffc0);
p = pb_push1(p, filter, 0x1012000);
pb_end(p);
}
{
auto p = pb_begin();
p = pb_push1(p, NV097_SET_FOG_ENABLE, false);
p = pb_push4(p, NV097_SET_TEXTURE_MATRIX_ENABLE, 0, 0, 0, 0);
p = pb_push1(p, NV097_SET_FRONT_FACE, NV097_SET_FRONT_FACE_V_CW);
p = pb_push1(p, NV097_SET_CULL_FACE, NV097_SET_CULL_FACE_V_BACK);
p = pb_push1(p, NV097_SET_CULL_FACE_ENABLE, true);
p = pb_push1(p, NV097_SET_COLOR_MASK,
NV097_SET_COLOR_MASK_BLUE_WRITE_ENABLE | NV097_SET_COLOR_MASK_GREEN_WRITE_ENABLE |
NV097_SET_COLOR_MASK_RED_WRITE_ENABLE | NV097_SET_COLOR_MASK_ALPHA_WRITE_ENABLE);
p = pb_push1(p, NV097_SET_DEPTH_TEST_ENABLE, false);
p = pb_push1(p, NV097_SET_DEPTH_MASK, true);
p = pb_push1(p, NV097_SET_DEPTH_FUNC, NV097_SET_DEPTH_FUNC_V_LESS);
p = pb_push1(p, NV097_SET_STENCIL_TEST_ENABLE, false);
p = pb_push1(p, NV097_SET_STENCIL_MASK, true);
p = pb_push1(p, NV097_SET_NORMALIZATION_ENABLE, false);
// Prevent bleedover between tests by setting default values.
p = pb_push4f(p, NV097_SET_WEIGHT4F, 0.f, 0.f, 0.f, 0.f);
p = pb_push3f(p, NV097_SET_NORMAL3F, 0.f, 0.f, 0.f);
p = pb_push1(p, NV097_SET_DIFFUSE_COLOR4I, 0x00000000);
p = pb_push1(p, NV097_SET_SPECULAR_COLOR4I, 0x00000000);
p = pb_push1f(p, NV097_SET_SPECULAR_COLOR4I, 0.f);
p = pb_push1(p, NV097_SET_POINT_SIZE, 0x8);
p = pb_push4f(p, NV097_SET_TEXCOORD0_4F, 0.f, 0.f, 0.f, 0.f);
p = pb_push4f(p, NV097_SET_TEXCOORD1_4F, 0.f, 0.f, 0.f, 0.f);
p = pb_push4f(p, NV097_SET_TEXCOORD2_4F, 0.f, 0.f, 0.f, 0.f);
p = pb_push4f(p, NV097_SET_TEXCOORD3_4F, 0.f, 0.f, 0.f, 0.f);
pb_end(p);
}
host_.SetDefaultViewportAndFixedFunctionMatrices();
host_.SetDepthBufferFloatMode(false);
host_.SetVertexShaderProgram(nullptr);
SetDefaultTextureFormat();
host_.SetTextureStageEnabled(0, false);
host_.SetTextureStageEnabled(1, false);
host_.SetTextureStageEnabled(2, false);
host_.SetTextureStageEnabled(3, false);
host_.SetShaderStageProgram(TestHost::STAGE_NONE);
host_.SetShaderStageInput(0, 0);
PixelShaderProgram::LoadUntexturedPixelShader();
PixelShaderProgram::DisablePixelShader();
host_.ClearAllVertexAttributeStrideOverrides();
#ifdef ENABLE_PGRAPH_REGION_DIFF
pgraph_diff_.Capture();
#endif
TagNV2ATrace(2);
{
auto p = pb_begin();
p = pb_push1(p, NV097_SET_FOG_ENABLE, true);
p = pb_push1(p, NV097_SET_FOG_ENABLE, false);
pb_end(p);
}
TagNV2ATrace(4);
}
void TestSuite::TagNV2ATrace(uint32_t num_nops) {
ASSERT(num_nops < 32 && "Too many nops in TagNV2ATrace");
auto p = pb_begin();
for (auto i = 0; i < num_nops; ++i) p = pb_push1(p, NV097_NO_OPERATION, 0x00);
pb_end(p);
}
void TestSuite::Deinitialize() {
#ifdef ENABLE_PGRAPH_REGION_DIFF
pgraph_diff_.DumpDiff();
#endif
}
void TestSuite::SetupTest() {}
void TestSuite::TearDownTest() {}
std::chrono::steady_clock::time_point TestSuite::LogTestStart(const std::string& test_name) {
PrintMsg("Starting %s::%s\n", suite_name_.c_str(), test_name.c_str());
#ifdef ENABLE_PROGRESS_LOG
if (allow_saving_) {
Logger::Log() << "Starting " << suite_name_ << "::" << test_name << std::endl;
}
#endif
return std::chrono::high_resolution_clock::now();
}
void TestSuite::LogTestEnd(const std::string& test_name, std::chrono::steady_clock::time_point start_time) {
auto now = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count();
PrintMsg(" Completed '%s' in %lums\n", test_name.c_str(), elapsed);
#ifdef ENABLE_PROGRESS_LOG
if (allow_saving_) {
Logger::Log() << " Completed '" << test_name << "' in " << elapsed << "ms" << std::endl;
}
#endif
}