mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-11-06 04:07:22 +09:00
172 lines
6.8 KiB
C++
172 lines
6.8 KiB
C++
/**
|
|
* @file tests/unit/platform/windows/test_display_vram.cpp
|
|
* @brief Tests for Windows FP16 shader selection and cursor mask conversion.
|
|
*/
|
|
|
|
// test includes
|
|
#include "../../../tests_common.h"
|
|
|
|
#ifdef _WIN32
|
|
// standard includes
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <bit>
|
|
#include <cstdint>
|
|
#include <tuple>
|
|
|
|
// local includes
|
|
#include <src/platform/windows/display.h>
|
|
|
|
namespace platf::dxgi {
|
|
/**
|
|
* @brief Convert cursor mask bytes to pixels for XOR blending.
|
|
*
|
|
* @param img_data Raw DXGI cursor data.
|
|
* @param shape_info Cursor format and dimensions.
|
|
* @return Cursor pixels for XOR blending.
|
|
*/
|
|
util::buffer_t<std::uint8_t> make_cursor_xor_image(const util::buffer_t<std::uint8_t> &img_data, DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info);
|
|
|
|
/**
|
|
* @brief Convert cursor mask bytes to pixels for alpha blending.
|
|
*
|
|
* @param img_data Raw DXGI cursor data.
|
|
* @param shape_info Cursor format and dimensions.
|
|
* @return Cursor pixels for alpha blending.
|
|
*/
|
|
util::buffer_t<std::uint8_t> make_cursor_alpha_image(const util::buffer_t<std::uint8_t> &img_data, DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info);
|
|
} // namespace platf::dxgi
|
|
|
|
TEST(WindowsCursorTest, DecodesEveryMonochromeMaskCombinationAcrossByteBoundaries) {
|
|
// Each pair of AND/XOR bits selects black, white, transparent, or inverted.
|
|
util::buffer_t<std::uint8_t> masks {4};
|
|
masks[0] = 0x33;
|
|
masks[1] = 0x33;
|
|
masks[2] = 0x55;
|
|
masks[3] = 0x55;
|
|
const DXGI_OUTDUPL_POINTER_SHAPE_INFO shape {
|
|
.Type = DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME,
|
|
.Width = 16,
|
|
.Height = 2,
|
|
.Pitch = 2,
|
|
};
|
|
const auto alpha = platf::dxgi::make_cursor_alpha_image(masks, shape);
|
|
const auto xor_image = platf::dxgi::make_cursor_xor_image(masks, shape);
|
|
ASSERT_EQ(alpha.size(), 16U * sizeof(std::uint32_t));
|
|
ASSERT_EQ(xor_image.size(), alpha.size());
|
|
const std::array<std::uint32_t, 4> expected_alpha {0xFF000000, 0xFFFFFFFF, 0, 0};
|
|
const std::array<std::uint32_t, 4> expected_xor {0, 0, 0, 0xFFFFFFFF};
|
|
for (std::size_t pixel = 0; pixel < 16; ++pixel) {
|
|
std::array<std::uint8_t, 4> alpha_bytes;
|
|
std::array<std::uint8_t, 4> xor_bytes;
|
|
std::copy_n(alpha.begin() + pixel * 4, 4, alpha_bytes.begin());
|
|
std::copy_n(xor_image.begin() + pixel * 4, 4, xor_bytes.begin());
|
|
EXPECT_EQ(std::bit_cast<std::uint32_t>(alpha_bytes), expected_alpha[pixel % 4]);
|
|
EXPECT_EQ(std::bit_cast<std::uint32_t>(xor_bytes), expected_xor[pixel % 4]);
|
|
}
|
|
}
|
|
|
|
TEST(WindowsCursorTest, StopsAtTheLastPixelInAPartialMaskByte) {
|
|
util::buffer_t<std::uint8_t> masks {2};
|
|
masks[0] = 0xFF;
|
|
masks[1] = 0xFF;
|
|
const DXGI_OUTDUPL_POINTER_SHAPE_INFO shape {
|
|
.Type = DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME,
|
|
.Width = 3,
|
|
.Height = 2,
|
|
.Pitch = 1,
|
|
};
|
|
const auto alpha = platf::dxgi::make_cursor_alpha_image(masks, shape);
|
|
const auto xor_image = platf::dxgi::make_cursor_xor_image(masks, shape);
|
|
EXPECT_EQ(alpha.size(), 12U);
|
|
EXPECT_EQ(xor_image.size(), 12U);
|
|
EXPECT_TRUE(std::all_of(alpha.begin(), alpha.end(), [](auto byte) {
|
|
return byte == 0;
|
|
}));
|
|
EXPECT_TRUE(std::all_of(xor_image.begin(), xor_image.end(), [](auto byte) {
|
|
return byte == 0xFF;
|
|
}));
|
|
}
|
|
|
|
TEST(WindowsCursorTest, ProcessesEveryMaskedColorPixelAndPreservesTheInput) {
|
|
const std::array<std::uint32_t, 3> pixels {0xFF112233, 0x00123456, 0x7F445566};
|
|
const auto bytes = std::bit_cast<std::array<std::uint8_t, 12>>(pixels);
|
|
util::buffer_t<std::uint8_t> input {bytes.size()};
|
|
std::ranges::copy(bytes, input.begin());
|
|
const DXGI_OUTDUPL_POINTER_SHAPE_INFO shape {
|
|
.Type = DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR,
|
|
.Width = 3,
|
|
.Height = 1,
|
|
.Pitch = 12,
|
|
};
|
|
|
|
const auto alpha = platf::dxgi::make_cursor_alpha_image(input, shape);
|
|
const auto xor_image = platf::dxgi::make_cursor_xor_image(input, shape);
|
|
const std::array<std::uint32_t, 3> expected_alpha {0, 0xFF123456, 0x7F445566};
|
|
const std::array<std::uint32_t, 3> expected_xor {0xFF112233, 0, 0x7F445566};
|
|
EXPECT_TRUE((std::ranges::equal(alpha, std::bit_cast<std::array<std::uint8_t, 12>>(expected_alpha))));
|
|
EXPECT_TRUE((std::ranges::equal(xor_image, std::bit_cast<std::array<std::uint8_t, 12>>(expected_xor))));
|
|
EXPECT_TRUE(std::ranges::equal(input, bytes));
|
|
}
|
|
|
|
using platf::dxgi::fp16_transfer_e;
|
|
using platf::dxgi::select_fp16_transfer;
|
|
|
|
/**
|
|
* @brief Encoder output format, HDR state, option state, and expected FP16 transfer.
|
|
*/
|
|
using Fp16TransferParam = std::tuple<DXGI_FORMAT, bool, bool, fp16_transfer_e>;
|
|
|
|
/**
|
|
* @brief Parameterized coverage for every output format with HDR and the opt-in option toggled.
|
|
*/
|
|
struct Fp16TransferTest: testing::TestWithParam<Fp16TransferParam> {};
|
|
|
|
TEST_P(Fp16TransferTest, SelectsExpectedTransfer) {
|
|
const auto &[format, hdr, gamma_encoded_sdr, expected] = GetParam();
|
|
|
|
EXPECT_EQ(expected, select_fp16_transfer(format, hdr, gamma_encoded_sdr));
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
LinearSdrByDefault,
|
|
Fp16TransferTest,
|
|
testing::Values(
|
|
Fp16TransferParam {DXGI_FORMAT_NV12, false, false, fp16_transfer_e::linear},
|
|
Fp16TransferParam {DXGI_FORMAT_P010, false, false, fp16_transfer_e::linear},
|
|
Fp16TransferParam {DXGI_FORMAT_R16_UINT, false, false, fp16_transfer_e::linear},
|
|
Fp16TransferParam {DXGI_FORMAT_AYUV, false, false, fp16_transfer_e::linear},
|
|
Fp16TransferParam {DXGI_FORMAT_Y410, false, false, fp16_transfer_e::linear}
|
|
)
|
|
);
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
GammaEncodedSdrWhenEnabled,
|
|
Fp16TransferTest,
|
|
testing::Values(
|
|
Fp16TransferParam {DXGI_FORMAT_NV12, false, true, fp16_transfer_e::gamma_encoded},
|
|
Fp16TransferParam {DXGI_FORMAT_P010, false, true, fp16_transfer_e::gamma_encoded},
|
|
Fp16TransferParam {DXGI_FORMAT_R16_UINT, false, true, fp16_transfer_e::gamma_encoded},
|
|
Fp16TransferParam {DXGI_FORMAT_AYUV, false, true, fp16_transfer_e::gamma_encoded},
|
|
Fp16TransferParam {DXGI_FORMAT_Y410, false, true, fp16_transfer_e::gamma_encoded}
|
|
)
|
|
);
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
HdrUnaffectedByOption,
|
|
Fp16TransferTest,
|
|
testing::Values(
|
|
Fp16TransferParam {DXGI_FORMAT_NV12, true, false, fp16_transfer_e::linear},
|
|
Fp16TransferParam {DXGI_FORMAT_NV12, true, true, fp16_transfer_e::linear},
|
|
Fp16TransferParam {DXGI_FORMAT_P010, true, false, fp16_transfer_e::perceptual_quantizer},
|
|
Fp16TransferParam {DXGI_FORMAT_P010, true, true, fp16_transfer_e::perceptual_quantizer},
|
|
Fp16TransferParam {DXGI_FORMAT_R16_UINT, true, false, fp16_transfer_e::perceptual_quantizer},
|
|
Fp16TransferParam {DXGI_FORMAT_R16_UINT, true, true, fp16_transfer_e::perceptual_quantizer},
|
|
Fp16TransferParam {DXGI_FORMAT_AYUV, true, false, fp16_transfer_e::linear},
|
|
Fp16TransferParam {DXGI_FORMAT_AYUV, true, true, fp16_transfer_e::linear},
|
|
Fp16TransferParam {DXGI_FORMAT_Y410, true, false, fp16_transfer_e::perceptual_quantizer},
|
|
Fp16TransferParam {DXGI_FORMAT_Y410, true, true, fp16_transfer_e::perceptual_quantizer}
|
|
)
|
|
);
|
|
#endif
|