/** * @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 #include #include #include #include // local includes #include 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 make_cursor_xor_image(const util::buffer_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 make_cursor_alpha_image(const util::buffer_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 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 expected_alpha {0xFF000000, 0xFFFFFFFF, 0, 0}; const std::array expected_xor {0, 0, 0, 0xFFFFFFFF}; for (std::size_t pixel = 0; pixel < 16; ++pixel) { std::array alpha_bytes; std::array 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(alpha_bytes), expected_alpha[pixel % 4]); EXPECT_EQ(std::bit_cast(xor_bytes), expected_xor[pixel % 4]); } } TEST(WindowsCursorTest, StopsAtTheLastPixelInAPartialMaskByte) { util::buffer_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 pixels {0xFF112233, 0x00123456, 0x7F445566}; const auto bytes = std::bit_cast>(pixels); util::buffer_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 expected_alpha {0, 0xFF123456, 0x7F445566}; const std::array expected_xor {0xFF112233, 0, 0x7F445566}; EXPECT_TRUE((std::ranges::equal(alpha, std::bit_cast>(expected_alpha)))); EXPECT_TRUE((std::ranges::equal(xor_image, std::bit_cast>(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; /** * @brief Parameterized coverage for every output format with HDR and the opt-in option toggled. */ struct Fp16TransferTest: testing::TestWithParam {}; 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