Adds 0x1D78 Z_MIN_MAX_CONTROL tests. (#123)

This commit is contained in:
Erik Abair 2023-07-22 09:25:32 -07:00 committed by GitHub
parent add9f6ccec
commit 20ed7289ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 529 additions and 17 deletions

View File

@ -146,6 +146,7 @@ generate_nv2a_vshinc_files(
src/shaders/fog_vec4_z.vsh
src/shaders/fog_vec4_zw.vsh
src/shaders/fog_vec4_unset.vsh
src/shaders/passthrough.vsh
)
generate_pixelshader_inl_files(
@ -366,6 +367,8 @@ add_executable(
src/tests/w_param_tests.h
src/tests/window_clip_tests.cpp
src/tests/window_clip_tests.h
src/tests/z_min_max_control_tests.cpp
src/tests/z_min_max_control_tests.h
src/tests/zero_stride_tests.cpp
src/tests/zero_stride_tests.h
${generated_vertex_shaders}

View File

@ -120,6 +120,47 @@ Assuming that this project has been checked out at `/development/pgraph_tester`:
the test. You may wish to utilize some of the helper methods from `TestHost`
and similar classes rather than using the raw output to improve readability.
### Writing nv2a vertex shaders in assembly
See [the README in the nv2a_vsh_asm repository](https://github.com/abaire/nv2a_vsh_asm) for an overview.
`*.vsh` files are assembed via the `generate_nv2a_vshinc_files` function in CMakeLists.txt. Each vsh file produces a
corresponding `.vshinc` file that contains a C-style list of 32-bit integers containing the vertex shader operations.
This file is intended to be included from test source files to initialize a constant array which may then be used to
populate a `VertexShaderProgram` via `SetShaderOverride`.
For example:
```c++
// Note that the VertexShaderProgram does not copy this data, so it is important that it remain in scope throughout
// the use of the VertexShaderProgram object.
static const uint32_t kPassthroughVsh[] = {
#include "passthrough.vshinc"
};
// ...
auto shader = std::make_shared<VertexShaderProgram>();
shader->SetShaderOverride(kPassthroughVsh, sizeof(kPassthroughVsh));
host_.SetVertexShaderProgram(shader);
```
Uniform values may then be set via the `VertexShaderProgram::SetUniform*` series of functions. By default, the 0th
uniform will be available in the shader as `c96`.
For example, a shader that takes a 4-element vertex might have the code:
```asm
#vertex vector 96
```
which would be populated via
```c++
shader->shader->SetUniformF(0, -1.f, 1.5f, 0.f, 1.f);
```
## Running with CLion
### On xemu

View File

@ -86,6 +86,7 @@
#include "tests/volume_texture_tests.h"
#include "tests/w_param_tests.h"
#include "tests/window_clip_tests.h"
#include "tests/z_min_max_control_tests.h"
#include "tests/zero_stride_tests.h"
#ifndef FALLBACK_OUTPUT_ROOT_PATH
@ -679,6 +680,10 @@ static void register_suites(TestHost& host, std::vector<std::shared_ptr<TestSuit
auto suite = std::make_shared<WindowClipTests>(host, output_directory);
test_suites.push_back(suite);
}
{
auto suite = std::make_shared<ZMinMaxControlTests>(host, output_directory);
test_suites.push_back(suite);
}
{
auto suite = std::make_shared<ZeroStrideTests>(host, output_directory);
test_suites.push_back(suite);

View File

@ -0,0 +1,15 @@
; A vertex shader that just passes through all parameters with no manipulation.
; Note that iWeight and iNormal are ignored as they'd generally be used in
; per-vertex lighting.
mov oPos, iPos
mov oDiffuse, iDiffuse
mov oSpecular, iSpecular
mov oFog, iFog
mov oPts, iPts
mov oBackDiffuse, iBackDiffuse
mov oBackSpecular, iBackSpecular
mov oTex0, iTex0
mov oTex1, iTex1
mov oTex2, iTex2
mov oTex3, iTex3

View File

@ -46,7 +46,10 @@ class ProjectionVertexShader : public VertexShaderProgram {
// Projects the given point (on the CPU), placing the resulting screen coordinates into `result`.
void ProjectPoint(vector_t &result, const vector_t &world_point) const;
//! Unprojects the given screen point, producing world coordinates that will project there.
void UnprojectPoint(vector_t &result, const vector_t &screen_point) const;
//! Unprojects the given screen point, producing world coordinates that will project there with the given Z value.
void UnprojectPoint(vector_t &result, const vector_t &screen_point, float world_z) const;
protected:

View File

@ -875,7 +875,7 @@ void TestHost::SaveRawTexture(const std::string &output_directory, const std::st
fclose(f);
}
void TestHost::SetupControl0(bool enable_stencil_write) const {
void TestHost::SetupControl0(bool enable_stencil_write, bool w_buffered) const {
// FIXME: Figure out what to do in cases where there are multiple stages with different conversion needs.
// Is this supported by hardware?
bool requires_colorspace_conversion = texture_stage_[0].RequiresColorspaceConversion();
@ -883,6 +883,7 @@ void TestHost::SetupControl0(bool enable_stencil_write) const {
uint32_t control0 = enable_stencil_write ? NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE : 0;
control0 |= MASK(NV097_SET_CONTROL0_Z_FORMAT,
depth_buffer_mode_float_ ? NV097_SET_CONTROL0_Z_FORMAT_FLOAT : NV097_SET_CONTROL0_Z_FORMAT_FIXED);
control0 |= MASK(NV097_SET_CONTROL0_Z_PERSPECTIVE_ENABLE, w_buffered ? 1 : 0);
if (requires_colorspace_conversion) {
control0 |= MASK(NV097_SET_CONTROL0_COLOR_SPACE_CONVERT, NV097_SET_CONTROL0_COLOR_SPACE_CONVERT_CRYCB_TO_RGB);
@ -1105,6 +1106,11 @@ void TestHost::BuildD3DProjectionViewportMatrix(matrix4_t &result, float fov, fl
MatrixMultMatrix(projection, viewport, result);
}
void TestHost::BuildD3DOrthographicProjectionMatrix(XboxMath::matrix4_t &result, float left, float right, float top,
float bottom, float z_near, float z_far) {
CreateD3DOrthographicLH(result, left, right, top, bottom, z_near, z_far);
}
void TestHost::BuildDefaultXDKProjectionMatrix(matrix4_t &matrix) const {
BuildD3DProjectionViewportMatrix(matrix, M_PI * 0.25f, 1.0f, 200.0f);
}
@ -1192,6 +1198,7 @@ void TestHost::SetFixedFunctionProjectionMatrix(const matrix4_t projection_matri
GetCompositeMatrix(fixed_function_composite_matrix_, fixed_function_model_view_matrix_,
fixed_function_projection_matrix_);
auto p = pb_begin();
p = pb_push_transposed_matrix(p, NV097_SET_COMPOSITE_MATRIX, fixed_function_composite_matrix_[0]);
pb_end(p);
@ -1200,6 +1207,11 @@ void TestHost::SetFixedFunctionProjectionMatrix(const matrix4_t projection_matri
MatrixInvert(fixed_function_composite_matrix_, fixed_function_inverse_composite_matrix_);
fixed_function_matrix_mode_ = MATRIX_MODE_USER;
// https://developer.download.nvidia.com/assets/gamedev/docs/W_buffering2.pdf
auto &proj = fixed_function_projection_matrix_;
w_near_ = proj[3][3] - (proj[3][2] / proj[2][2] * proj[2][3]);
w_far_ = (proj[3][3] - proj[3][2]) / (proj[2][2] - proj[2][3]) * proj[2][3] + proj[3][3];
}
void TestHost::SetTextureStageEnabled(uint32_t stage, bool enabled) {

View File

@ -342,6 +342,10 @@ class TestHost {
// Gets a D3D-style matrix suitable for a projection + viewport transform.
void BuildD3DProjectionViewportMatrix(matrix4_t &result, float fov, float z_near, float z_far) const;
//! Builds an orthographic projection matrix.
static void BuildD3DOrthographicProjectionMatrix(matrix4_t &result, float left, float right, float top, float bottom,
float z_near, float z_far);
// Gets a reasonable default model view matrix (camera at z=-7.0f looking at the origin)
static void BuildDefaultXDKModelViewMatrix(matrix4_t &matrix);
// Gets a reasonable default projection matrix (fov = PI/4, near = 1, far = 200)
@ -372,6 +376,9 @@ class TestHost {
inline const matrix4_t &GetFixedFunctionModelViewMatrix() const { return fixed_function_model_view_matrix_; }
inline const matrix4_t &GetFixedFunctionProjectionMatrix() const { return fixed_function_projection_matrix_; }
float GetWNear() const { return w_near_; }
float GetWFar() const { return w_far_; }
// Start the process of rendering an inline-defined primitive (specified via SetXXXX methods below).
// Note that End() must be called to trigger rendering, and that SetVertex() triggers the creation of a vertex.
void Begin(DrawPrimitive primitive) const;
@ -526,7 +533,8 @@ class TestHost {
}
}
void SetupControl0(bool enable_stencil_write = true) const;
//! Set up the control0 register, controlling stencil writing and depth buffer mode.
void SetupControl0(bool enable_stencil_write = true, bool w_buffered = false) const;
// Commit any changes to texture stages (called automatically in PrepareDraw but may be useful to call more frequently
// in scenes with multiple draws per clear)
@ -604,6 +612,9 @@ class TestHost {
matrix4_t fixed_function_composite_matrix_{};
matrix4_t fixed_function_inverse_composite_matrix_{};
float w_near_{0.f};
float w_far_{0.f};
bool save_results_{true};
uint32_t vertex_attribute_stride_override_[16]{

View File

@ -120,7 +120,7 @@ void ColorKeyTests::TearDownTest() {
pb_end(p);
}
static void add_vertex(TestHost& host, float x, float y, float u, float v) {
static void AddVertex(TestHost& host, float x, float y, float u, float v) {
host.SetDiffuse(0.4f, 0.1f, 0.8f);
host.SetTexCoord0(u, v);
host.SetTexCoord1(u, v);
@ -138,10 +138,10 @@ static void DrawQuads(TestHost& host, float x = 0.f, float y = 0.f) {
auto size = 0.75f;
add_vertex(host, -size + x, size + y, 0.f * kTextureSize, 0.f * kTextureSize);
add_vertex(host, size + x, size + y, 1.f * kTextureSize, 0.f * kTextureSize);
add_vertex(host, size + x, -size + y, 1.f * kTextureSize, 1.f * kTextureSize);
add_vertex(host, -size + x, -size + y, 0.f * kTextureSize, 1.f * kTextureSize);
AddVertex(host, -size + x, size + y, 0.f * kTextureSize, 0.f * kTextureSize);
AddVertex(host, size + x, size + y, 1.f * kTextureSize, 0.f * kTextureSize);
AddVertex(host, size + x, -size + y, 1.f * kTextureSize, 1.f * kTextureSize);
AddVertex(host, -size + x, -size + y, 0.f * kTextureSize, 1.f * kTextureSize);
host.End();
}

View File

@ -10,7 +10,7 @@
#include "vertex_buffer.h"
static constexpr uint32_t kF16MaxFixedRepresentation = 0x0000FFFF;
static constexpr uint32_t kF24MaxFixedRepresentation = 0x00FEFFFF;
// static constexpr uint32_t kF24MaxFixedRepresentation = 0x00FEFFFF;
// Keep in sync with the value used to set up the default XDK composite matrix.
static constexpr float kCameraZ = -7.0f;

View File

@ -10,7 +10,7 @@
#include "vertex_buffer.h"
static constexpr uint32_t kF16MaxFixedRepresentation = 0x0000FFFF;
static constexpr uint32_t kF24MaxFixedRepresentation = 0x00FEFFFF;
// static constexpr uint32_t kF24MaxFixedRepresentation = 0x00FEFFFF;
constexpr DepthFormatTests::DepthFormat kDepthFormats[] = {
{NV097_SET_SURFACE_FORMAT_ZETA_Z16, 0x0000FFFF, false},

View File

@ -13,7 +13,7 @@
#include "texture_generator.h"
static constexpr const char kStopBehavior[] = "Stop";
static constexpr const char kAlternateStop[] = "Stop Alt";
// static constexpr const char kAlternateStop[] = "Stop Alt";
static constexpr const char kSizeInMaxUnity[] = "Size In Max - dI/dO = 1";
static constexpr const char kSizeInMaxLarge[] = "Size In Max - dI/dO > 1";

View File

@ -92,6 +92,10 @@ void TestSuite::Initialize() {
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));

View File

@ -137,7 +137,10 @@ TexgenMatrixTests::TexgenMatrixTests(TestHost &host, std::string output_dir)
std::string test_name = name + "_Arbitrary";
tests_[test_name] = [this, test_name, mode]() {
matrix4_t matrix = {
0.7089392, 0.0, 0.515, 0.0, 0.0, 1.2603364, 0.49, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
{0.7089392, 0.0, 0.515, 0.0},
{0.0, 1.2603364, 0.49, 0.0},
{0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0},
};
Test(test_name, matrix, mode);
};

View File

@ -726,7 +726,7 @@ void TextureBorderTests::TestCubemapBorderedSwizzled(const std::string &name, ui
auto draw = [this, &shader, width](float x, float y, float z, float r_x, float r_y, float r_z,
bool include_border = false) {
matrix4_t matrix = {0.0f};
matrix4_t matrix;
vector_t eye{0.0f, 0.0f, -7.0f, 1.0f};
vector_t at{0.0f, 0.0f, 0.0f, 1.0f};
vector_t up{0.0f, 1.0f, 0.0f, 1.0f};

View File

@ -153,7 +153,7 @@ void TextureCubemapTests::TestCubemap() {
auto shader = std::static_pointer_cast<PerspectiveVertexShader>(host_.GetShaderProgram());
auto draw = [this, &shader](float x, float y, float z, float r_x, float r_y, float r_z) {
matrix4_t matrix = {0.0f};
matrix4_t matrix;
vector_t eye{0.0f, 0.0f, -7.0f, 1.0f};
vector_t at{0.0f, 0.0f, 0.0f, 1.0f};
vector_t up{0.0f, 1.0f, 0.0f, 1.0f};
@ -239,11 +239,11 @@ void TextureCubemapTests::TestDotSTRCubemap(const std::string &name, uint32_t do
host_.PrepareDraw(0xFE131313);
auto draw = [this, &shader](float x, float y, float z, float r_x, float r_y, float r_z) {
matrix4_t matrix = {0.0f};
matrix4_t matrix;
vector_t eye{0.0f, 0.0f, -7.0f, 1.0f};
vector_t at{0.0f, 0.0f, 0.0f, 1.0f};
vector_t up{0.0f, 1.0f, 0.0f, 1.0f};
host_.BuildD3DModelViewMatrix(matrix, eye, at, up);
TestHost::BuildD3DModelViewMatrix(matrix, eye, at, up);
auto &model_matrix = shader->GetModelMatrix();
MatrixSetIdentity(model_matrix);

View File

@ -121,7 +121,10 @@ TextureMatrixTests::TextureMatrixTests(TestHost &host, std::string output_dir)
constexpr char kTestName[] = "Arbitrary";
tests_[kTestName] = [this, kTestName]() {
matrix4_t matrix = {
0.7089392, 0.0, 0.515, 0.0, 0.0, 1.2603364, 0.49, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
{0.7089392, 0.0, 0.515, 0.0},
{0.0, 1.2603364, 0.49, 0.0},
{0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0},
};
Test(kTestName, matrix);
};

View File

@ -0,0 +1,360 @@
#include "z_min_max_control_tests.h"
#include <pbkit/pbkit.h>
#include "debug_output.h"
#include "pbkit_ext.h"
#include "shaders/perspective_vertex_shader.h"
#include "texture_generator.h"
#include "vertex_buffer.h"
#include "xbox_math_d3d.h"
#include "xbox_math_matrix.h"
constexpr uint32_t kSmallSize = 16;
constexpr uint32_t kSmallSpacing = 4;
constexpr uint32_t kStep = kSmallSize + kSmallSpacing;
static constexpr const char kTestName[] = "Ctrl";
static constexpr const char kTestFixedName[] = "CtrlFixed";
static constexpr uint32_t kBackgroundColor = 0xFF222228;
static constexpr float kZNear = 10.f;
static constexpr float kZFar = 100.f;
static constexpr float kWNear = 10.f;
static constexpr float kWFar = 100.f;
static std::string MakeTestName(const char* prefix, uint32_t mode, bool w_buffered);
ZMinMaxControlTests::ZMinMaxControlTests(TestHost& host, std::string output_dir)
: TestSuite(host, std::move(output_dir), "ZMinMaxControl") {
for (auto w_buffered : {false, true}) {
for (auto cull :
{NV097_SET_ZMIN_MAX_CONTROL_CULL_NEAR_FAR_EN_FALSE, NV097_SET_ZMIN_MAX_CONTROL_CULL_NEAR_FAR_EN_TRUE}) {
for (auto z_clamp : {NV097_SET_ZMIN_MAX_CONTROL_ZCLAMP_EN_CULL, NV097_SET_ZMIN_MAX_CONTROL_ZCLAMP_EN_CLAMP}) {
for (auto ignore_w :
{NV097_SET_ZMIN_MAX_CONTROL_CULL_IGNORE_W_FALSE, NV097_SET_ZMIN_MAX_CONTROL_CULL_IGNORE_W_TRUE}) {
uint32_t mode = cull | z_clamp | ignore_w;
{
std::string name = MakeTestName(kTestName, mode, w_buffered);
tests_[name] = [this, name, mode, w_buffered]() { this->Test(name, mode, w_buffered); };
}
{
std::string name = MakeTestName(kTestFixedName, mode, w_buffered);
tests_[name] = [this, name, mode, w_buffered]() { this->TestFixed(name, mode, w_buffered); };
}
}
}
}
}
const auto fb_width = host.GetFramebufferWidthF();
const auto fb_height = host.GetFramebufferHeightF();
kLeft = floorf(fb_width / 5.0f);
kRight = fb_width - kLeft;
kTop = floorf(fb_height / 10.0f);
kBottom = fb_height - kTop;
kRegionWidth = (kRight - kLeft) * 0.33f;
kRegionHeight = (kBottom - kTop) * 0.5f;
quads_per_row_ = static_cast<uint32_t>(kRegionWidth - kSmallSize) / kStep;
quads_per_col_ = static_cast<uint32_t>(kRegionHeight - kSmallSize) / kStep;
col_size_ = static_cast<float>(kSmallSize) + static_cast<float>(quads_per_col_) * kStep;
num_quads_ = quads_per_row_ * quads_per_col_;
}
void ZMinMaxControlTests::Initialize() { TestSuite::Initialize(); }
void ZMinMaxControlTests::TearDownTest() {
TestSuite::TearDownTest();
host_.SetupControl0();
host_.SetSurfaceFormat(TestHost::SCF_A8R8G8B8, TestHost::SZF_Z16, host_.GetFramebufferWidth(),
host_.GetFramebufferHeight());
auto p = pb_begin();
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);
pb_end(p);
}
static void AddVertex(TestHost& host, const vector_t& position, float r, float g, float b) {
host.SetDiffuse(r, g, b);
host.SetVertex(position);
};
// clang-format off
static const uint32_t kPassthroughVsh[] = {
#include "passthrough.vshinc"
};
// clang-format on
void ZMinMaxControlTests::DrawBlock(float x_offset, float y_offset, ZMinMaxDrawMode zw_mode, bool projected) const {
const float z_min = 0.f;
const float z_max = kZFar * 1.5f;
const float w_min = 0.f;
const float w_max = kWFar * 1.5f;
float z_inc = (z_max - z_min) / (static_cast<float>(num_quads_) + 1.f);
float w_inc = (w_max - w_min) / (static_cast<float>(num_quads_) + 1.f);
float z_left = z_min;
float w_left = w_min;
float right_offset_z = z_inc * 0.75f;
float right_offset_w = w_inc * 0.75f;
float y = y_offset;
for (int y_idx = 0; y_idx < quads_per_col_; ++y_idx) {
float x = x_offset;
for (int x_idx = 0; x_idx < quads_per_row_; ++x_idx) {
float z_right = z_left + right_offset_z;
float w_right = w_left + right_offset_w;
Color left;
Color right;
const float left_z_color = 0.25f + z_left / z_max * 0.75f;
const float right_z_color = 0.25f + z_right / z_max * 0.75f;
const float left_w_color = 0.25f + w_left / w_max * 0.75f;
const float right_w_color = 0.25f + w_right / w_max * 0.75f;
switch (zw_mode) {
case M_Z_INC_W_ONE:
left.SetGrey(left_z_color);
right.SetGrey(right_z_color);
w_left = 1.f;
w_right = 1.f;
break;
case M_Z_INC_W_INC: {
left.SetRGB(left_z_color, 0.25f, left_w_color);
right.SetRGB(right_z_color, 0.25f, right_w_color);
} break;
case M_Z_NF_W_INC:
left.SetRGB(0.33f, 0.25f, left_w_color);
right.SetRGB(0.33f, 0.25f, right_w_color);
z_left = kZNear * 0.8f;
z_right = kZFar * 1.2f;
break;
case M_Z_NF_W_NF:
left.SetRGB(0.33f, 0.75f, 0.25f);
right.SetRGB(0.33f, 0.75f, 0.8f);
z_left = kZNear * 0.8f;
z_right = kZFar * 1.2f;
w_left = kWNear * 0.8f;
w_right = kWFar * 1.2f;
break;
case M_Z_INC_W_TEN:
left.SetRGB(left_z_color, left_z_color, 0.25f);
right.SetRGB(right_z_color, right_z_color, 0.8f);
w_left = 10.f;
w_right = 10.f;
break;
case M_Z_INC_W_FRAC:
left.SetRGB(0.75f, left_z_color, left_z_color);
right.SetRGB(right_z_color, right_z_color, 0.8f);
w_left = 0.01f;
w_right = 0.0001f;
break;
case M_Z_INC_W_INV_Z:
left.SetRGB(0.5f, left_z_color, 0.5f);
right.SetRGB(0.5f, right_z_color, 0.5f);
w_left = 1.f / z_left;
w_right = 1.f / z_right;
}
if (!projected) {
AddVertex(host_, {x, y, z_left, w_left}, left.r, left.g, left.b);
AddVertex(host_, {x + kSmallSize, y, z_right, w_right}, right.r, right.g, right.b);
AddVertex(host_, {x + kSmallSize, y + kSmallSize, z_right, w_right}, right.r, right.g, right.b);
AddVertex(host_, {x, y + kSmallSize, z_left, w_left}, left.r, left.g, left.b);
} else {
auto w_adjust = [](vector_t& pt, float w) {
pt[0] *= w;
pt[1] *= w;
pt[2] *= w;
pt[3] = w;
};
vector_t world_pt;
host_.UnprojectPoint(world_pt, {x, y, z_left, 1.f});
w_adjust(world_pt, w_left);
AddVertex(host_, world_pt, left.r, left.g, left.b);
host_.UnprojectPoint(world_pt, {x + kSmallSize, y, z_right, 1.f});
// host_.UnprojectPoint(world_pt, {x + kSmallSize, y, 0.f, 1.f}, z_right);
w_adjust(world_pt, w_right);
AddVertex(host_, world_pt, right.r, right.g, right.b);
host_.UnprojectPoint(world_pt, {x + kSmallSize, y + kSmallSize, z_right, 1.f});
// host_.UnprojectPoint(world_pt, {x + kSmallSize, y + kSmallSize, 0.f, 1.f}, z_right);
w_adjust(world_pt, w_right);
AddVertex(host_, world_pt, right.r, right.g, right.b);
host_.UnprojectPoint(world_pt, {x, y + kSmallSize, z_left, 1.f});
// host_.UnprojectPoint(world_pt, {x, y + kSmallSize, 0.f, 1.f}, z_left);
w_adjust(world_pt, w_left);
AddVertex(host_, world_pt, left.r, left.g, left.b);
}
z_left += z_inc;
w_left += w_inc;
x += kStep;
}
y += kStep;
}
}
void ZMinMaxControlTests::Test(const std::string& name, uint32_t mode, bool w_buffered) {
auto shader = std::make_shared<VertexShaderProgram>();
shader->SetShaderOverride(kPassthroughVsh, sizeof(kPassthroughVsh));
host_.SetVertexShaderProgram(shader);
host_.PrepareDraw(kBackgroundColor);
if (w_buffered) {
host_.SetDepthClip(kWNear, kWFar);
} else {
host_.SetDepthClip(kZNear, kZFar);
}
auto p = pb_begin();
p = pb_push1(p, NV097_SET_ZMIN_MAX_CONTROL, mode);
pb_end(p);
const float zscale = host_.GetMaxDepthBufferValue();
host_.SetupControl0(false, w_buffered);
TestHost::SetViewportScale(320.f, -240.f, zscale, w_buffered ? 1.f : 0.f);
host_.Begin(TestHost::PRIMITIVE_QUADS);
float x_offset = 90.f;
float y_offset = kTop + kSmallSpacing + (kRegionHeight - col_size_) * 0.5f;
DrawBlock(x_offset, y_offset, M_Z_INC_W_ONE);
DrawBlock(x_offset, y_offset + kRegionHeight, M_Z_NF_W_INC);
x_offset += kRegionWidth + 90.f;
DrawBlock(x_offset, y_offset, M_Z_INC_W_FRAC);
DrawBlock(x_offset, y_offset + kRegionHeight, M_Z_NF_W_NF);
x_offset += kRegionWidth + 90.f;
DrawBlock(x_offset, y_offset, M_Z_INC_W_INC);
DrawBlock(x_offset, y_offset + kRegionHeight, M_Z_INC_W_TEN);
host_.End();
pb_print("%s\n", name.c_str());
pb_printat(2, 1, (char*)"Z=Inc");
pb_printat(2, 21, (char*)"Z=Inc");
pb_printat(2, 44, (char*)"Z=Inc");
pb_printat(3, 1, (char*)"W=1");
pb_printat(3, 21, (char*)"W=Frac");
pb_printat(3, 44, (char*)"W=Inc");
pb_printat(11, 1, (char*)"Z=N->F");
pb_printat(11, 21, (char*)"Z=N->F");
pb_printat(11, 44, (char*)"Z=Inc");
pb_printat(12, 1, (char*)"W=Inc");
pb_printat(12, 21, (char*)"W=N->F");
pb_printat(12, 44, (char*)"W=10");
pb_draw_text_screen();
host_.FinishDraw(allow_saving_, output_dir_, name);
}
void ZMinMaxControlTests::TestFixed(const std::string& name, uint32_t mode, bool w_buffered) {
host_.SetVertexShaderProgram(nullptr);
host_.SetXDKDefaultViewportAndFixedFunctionMatrices();
host_.PrepareDraw(kBackgroundColor);
TestHost::SetViewportScale(0.f, 0.f, 0.f, 0.f);
matrix4_t matrix;
XboxMath::MatrixSetIdentity(matrix);
XboxMath::MatrixTranslate(matrix, {0.f, 0.f, -3.f, 1.f});
host_.SetFixedFunctionModelViewMatrix(matrix);
const auto near_plane = w_buffered ? kWNear : kZNear;
const auto far_plane = w_buffered ? kWFar : kZFar;
TestHost::BuildD3DOrthographicProjectionMatrix(matrix, -320.f, 320.f, 240.f, -240.f, near_plane, far_plane);
matrix4_t viewport;
const auto fb_width = host_.GetFramebufferWidthF();
const auto fb_height = host_.GetFramebufferHeightF();
XboxMath::CreateD3DStandardViewport16Bit(viewport, fb_width, fb_height);
matrix4_t proj_viewport;
MatrixMultMatrix(matrix, viewport, proj_viewport);
host_.SetFixedFunctionProjectionMatrix(proj_viewport);
host_.SetupControl0(false, w_buffered);
if (w_buffered) {
host_.SetDepthClip(kWNear, kWFar);
} else {
host_.SetDepthClip(kZNear, kZFar);
}
auto p = pb_begin();
p = pb_push1(p, NV097_SET_ZMIN_MAX_CONTROL, mode);
pb_end(p);
const float zscale = host_.GetMaxDepthBufferValue();
host_.SetupControl0(false, w_buffered);
TestHost::SetViewportScale(320.f, -240.f, zscale, w_buffered ? 1.f : 0.f);
host_.Begin(TestHost::PRIMITIVE_QUADS);
float x_offset = 90.f;
float y_offset = kTop + kSmallSpacing + (kRegionHeight - col_size_) * 0.5f;
DrawBlock(x_offset, y_offset, M_Z_INC_W_ONE, true);
DrawBlock(x_offset, y_offset + kRegionHeight, M_Z_NF_W_INC, true);
x_offset += kRegionWidth + 90.f;
DrawBlock(x_offset, y_offset, M_Z_INC_W_FRAC, true);
DrawBlock(x_offset, y_offset + kRegionHeight, M_Z_NF_W_NF, true);
x_offset += kRegionWidth + 90.f;
DrawBlock(x_offset, y_offset, M_Z_INC_W_INC, true);
DrawBlock(x_offset, y_offset + kRegionHeight, M_Z_INC_W_TEN, true);
host_.End();
pb_print("%s\n", name.c_str());
pb_printat(2, 1, (char*)"Z=Inc");
pb_printat(2, 21, (char*)"Z=Inc");
pb_printat(2, 44, (char*)"Z=Inc");
pb_printat(3, 1, (char*)"W=1");
pb_printat(3, 21, (char*)"W=Frac");
pb_printat(3, 44, (char*)"W=Inc");
pb_printat(11, 1, (char*)"Z=N->F");
pb_printat(11, 21, (char*)"Z=N->F");
pb_printat(11, 44, (char*)"Z=Inc");
pb_printat(12, 1, (char*)"W=Inc");
pb_printat(12, 21, (char*)"W=N->F");
pb_printat(12, 44, (char*)"W=10");
pb_draw_text_screen();
host_.FinishDraw(allow_saving_, output_dir_, name);
}
static std::string MakeTestName(const char* prefix, uint32_t mode, bool w_buffered) {
std::string ret = prefix;
ret += w_buffered ? "_WBuf" : "";
ret += (mode & NV097_SET_ZMIN_MAX_CONTROL_CULL_NEAR_FAR_EN_TRUE) ? "_NEARFAR" : "";
ret += (mode & NV097_SET_ZMIN_MAX_CONTROL_ZCLAMP_EN_CLAMP) ? "_ZCLAMP" : "_ZCULL";
ret += (mode & NV097_SET_ZMIN_MAX_CONTROL_CULL_IGNORE_W_TRUE) ? "_IgnW" : "";
return ret;
}

View File

@ -0,0 +1,52 @@
#ifndef NXDK_PGRAPH_TESTS_Z_MIN_MAX_CONTROL_TESTS_H
#define NXDK_PGRAPH_TESTS_Z_MIN_MAX_CONTROL_TESTS_H
#include <memory>
#include <vector>
#include "test_host.h"
#include "test_suite.h"
class TestHost;
class VertexBuffer;
// Tests 0x1D78 NV097_SET_ZMIN_MAX_CONTROL functions.
class ZMinMaxControlTests : public TestSuite {
public:
typedef enum ZMinMaxDrawMode {
M_Z_INC_W_ONE,
M_Z_INC_W_INC,
M_Z_NF_W_INC,
M_Z_NF_W_NF,
M_Z_INC_W_TEN,
M_Z_INC_W_FRAC,
M_Z_INC_W_INV_Z,
} ZMinMaxDrawMode;
public:
ZMinMaxControlTests(TestHost& host, std::string output_dir);
void Initialize() override;
void TearDownTest() override;
private:
void Test(const std::string& name, uint32_t mode, bool w_buffered);
void TestFixed(const std::string& name, uint32_t mode, bool w_buffered);
void DrawBlock(float x_offset, float y_offset, ZMinMaxDrawMode zw_mode, bool projected = false) const;
private:
float kLeft{0.f};
float kRight{0.f};
float kTop{0.f};
float kBottom{0.f};
float kRegionWidth{0.f};
float kRegionHeight{0.f};
uint32_t quads_per_row_{0};
uint32_t quads_per_col_{0};
float col_size_{0.f};
uint32_t num_quads_{0};
};
#endif // NXDK_PGRAPH_TESTS_Z_MIN_MAX_CONTROL_TESTS_H

@ -1 +1 @@
Subproject commit bff2424b219959ecaf4c79b344132029c6fab3a6
Subproject commit a898f1f93f66d6fd2c7ae4eef64a5643809dc7ad