| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/graphics/display/drivers/intel-display/pipe.h" |
| |
| #include <lib/driver/fake-mmio-reg/cpp/fake-mmio-reg.h> |
| #include <lib/driver/testing/cpp/scoped_global_logger.h> |
| #include <lib/mmio/mmio-buffer.h> |
| #include <lib/sysmem-version/sysmem-version.h> |
| |
| #include <array> |
| #include <cstdint> |
| #include <map> |
| #include <optional> |
| #include <vector> |
| |
| #include <gtest/gtest.h> |
| |
| #include "src/graphics/display/drivers/intel-display/gtt.h" |
| #include "src/graphics/display/drivers/intel-display/hardware-common.h" |
| #include "src/graphics/display/lib/api-types/cpp/alpha-mode.h" |
| #include "src/graphics/display/lib/api-types/cpp/color-conversion.h" |
| #include "src/graphics/display/lib/api-types/cpp/coordinate-transformation.h" |
| #include "src/graphics/display/lib/api-types/cpp/driver-config-stamp.h" |
| #include "src/graphics/display/lib/api-types/cpp/driver-image-id.h" |
| #include "src/graphics/display/lib/api-types/cpp/driver-layer.h" |
| #include "src/graphics/display/lib/api-types/cpp/image-metadata.h" |
| #include "src/graphics/display/lib/api-types/cpp/image-tiling-type.h" |
| #include "src/graphics/display/lib/api-types/cpp/pixel-format.h" |
| |
| namespace intel_display { |
| |
| class PipeTest : public ::testing::Test { |
| public: |
| PipeTest() = default; |
| |
| void SetUp() override { mmio_buffer_.emplace(reg_region_.GetMmioBuffer()); } |
| |
| void TearDown() override {} |
| |
| protected: |
| constexpr static uint32_t kMinimumRegCount = 0xd0000 / sizeof(uint32_t); |
| fdf_testing::ScopedGlobalLogger logger_; |
| fake_mmio::FakeMmioRegRegion reg_region_{sizeof(uint32_t), kMinimumRegCount}; |
| std::optional<fdf::MmioBuffer> mmio_buffer_; |
| }; |
| |
| namespace { |
| |
| class TestGttRegionImpl : public GttRegion { |
| public: |
| explicit TestGttRegionImpl(uint64_t handle) : handle_(handle) {} |
| |
| uint64_t bytes_per_row() const override { return 64; } |
| uint64_t base() const override { return handle_ + 0xf0000000; } |
| |
| private: |
| uint64_t handle_ = 0; |
| }; |
| |
| std::map<display::DriverImageId, TestGttRegionImpl> region_map; |
| |
| PixelFormatAndModifier GetPixelFormat(display::DriverImageId image_id) { |
| return PixelFormatAndModifier( |
| fuchsia_images2::PixelFormat::kB8G8R8A8, |
| /*pixel_format_modifier_param=*/fuchsia_images2::PixelFormatModifier::kLinear); |
| } |
| |
| const GttRegion& GetGttImageHandle(const display::ImageMetadata& image_metadata, |
| display::DriverImageId image_handle, |
| display::CoordinateTransformation coordinate_transformation) { |
| auto it = region_map.find(image_handle); |
| if (it != region_map.end()) { |
| return it->second; |
| } |
| return region_map.try_emplace(image_handle, image_handle.value()).first->second; |
| } |
| |
| display::DriverLayer CreatePrimaryLayerConfig(display::DriverImageId image_id) { |
| static constexpr int32_t kWidth = 1024; |
| static constexpr int32_t kHeight = 768; |
| |
| return display::DriverLayer({ |
| .display_destination = {{.x = 0, .y = 0, .width = kWidth, .height = kHeight}}, |
| .image_source = {{.x = 0, .y = 0, .width = kWidth, .height = kHeight}}, |
| .image_id = image_id, |
| .image_metadata = {{.width = kWidth, |
| .height = kHeight, |
| .tiling_type = display::ImageTilingType::kLinear}}, |
| .fallback_color = {{ |
| .format = display::PixelFormat::kB8G8R8A8, |
| .bytes = {{0xaa, 0xbb, 0xcc, 0xdd, 0, 0, 0, 0}}, |
| }}, |
| .alpha_mode = display::AlphaMode::kDisable, |
| .alpha_coefficient = 0.0f, |
| .image_source_transformation = display::CoordinateTransformation::kIdentity, |
| }); |
| } |
| |
| } // namespace |
| |
| TEST_F(PipeTest, TiedTranscoderId) { |
| PipeSkylake pipe_a(&mmio_buffer_.value(), PipeId::PIPE_A, {}); |
| EXPECT_EQ(TranscoderId::TRANSCODER_A, pipe_a.tied_transcoder_id()); |
| |
| PipeSkylake pipe_b(&mmio_buffer_.value(), PipeId::PIPE_B, {}); |
| EXPECT_EQ(TranscoderId::TRANSCODER_B, pipe_b.tied_transcoder_id()); |
| |
| PipeSkylake pipe_c(&mmio_buffer_.value(), PipeId::PIPE_C, {}); |
| EXPECT_EQ(TranscoderId::TRANSCODER_C, pipe_c.tied_transcoder_id()); |
| |
| // TODO(https://fxbug.dev/42060657): Add a test for transcoder D, when we support it. |
| } |
| |
| // Verifies that GetVsyncConfigStamp() could return the correct config stamp |
| // given different image handles from device registers. |
| TEST_F(PipeTest, GetVsyncConfigStamp) { |
| PipeSkylake pipe(&*mmio_buffer_, PipeId::PIPE_A, {}); |
| |
| display::DriverImageId kImageHandle1(0x1111u); |
| display::DriverImageId kImageHandle2(0x2222u); |
| display::DriverImageId kImageHandle3(0x3333u); |
| display::DriverLayer layer_1 = CreatePrimaryLayerConfig(kImageHandle1); |
| display::DriverLayer layer_2 = CreatePrimaryLayerConfig(kImageHandle2); |
| display::DriverLayer layer_3 = CreatePrimaryLayerConfig(kImageHandle3); |
| |
| // Applies configuration with only one layer (layer_1). |
| const std::array<display::DriverLayer, 1> test_layers1 = {layer_1}; |
| display::DriverConfigStamp stamp_1{1}; |
| pipe.ApplyConfiguration(display::ColorConversion::kIdentity, test_layers1, stamp_1, |
| GetGttImageHandle, GetPixelFormat); |
| |
| // For images that are not registered with Pipe yet, GetVsyncConfigStamp() |
| // should return nullopt. |
| display::DriverConfigStamp vsync_config_stamp_not_found = |
| pipe.GetVsyncConfigStamp({kImageHandle2}); |
| EXPECT_EQ(vsync_config_stamp_not_found, display::kInvalidDriverConfigStamp); |
| |
| // Otherwise, for a valid image handle that has occurred in a past config, |
| // GetVsyncConfigStamp() should return the latest config where it occurred. |
| display::DriverConfigStamp vsync_config_stamp_1 = pipe.GetVsyncConfigStamp({kImageHandle1}); |
| EXPECT_NE(vsync_config_stamp_1, display::kInvalidDriverConfigStamp); |
| EXPECT_EQ(vsync_config_stamp_1, stamp_1); |
| |
| // Applies another configuration with two layers (layer_2 replacing layer_1, |
| // and a new layer layer_3). |
| const std::array<display::DriverLayer, 2> test_layers2 = {layer_2, layer_3}; |
| display::DriverConfigStamp stamp_2{2}; |
| pipe.ApplyConfiguration(display::ColorConversion::kIdentity, test_layers2, stamp_2, |
| GetGttImageHandle, GetPixelFormat); |
| |
| // It is possible that a layer update is slower than other layers, so on |
| // Vsync time the device may have layers from different configurations. In |
| // that case, the device should return the oldest configuration stamp, i.e. |
| // stamp_1. |
| display::DriverConfigStamp vsync_config_stamp_2 = |
| pipe.GetVsyncConfigStamp({kImageHandle1, kImageHandle3}); |
| EXPECT_NE(vsync_config_stamp_2, display::kInvalidDriverConfigStamp); |
| EXPECT_EQ(vsync_config_stamp_2, stamp_1); |
| |
| // Now both layers are updated in another new Vsync. GetVsyncConfigStamp() |
| // should return the updated stamp value. |
| display::DriverConfigStamp vsync_config_stamp_3 = |
| pipe.GetVsyncConfigStamp({kImageHandle2, kImageHandle3}); |
| EXPECT_NE(vsync_config_stamp_3, display::kInvalidDriverConfigStamp); |
| EXPECT_EQ(vsync_config_stamp_3, stamp_2); |
| |
| // Old image handle should be evicted from Pipe completely. |
| display::DriverConfigStamp vsync_config_stamp_4 = |
| pipe.GetVsyncConfigStamp({kImageHandle1, kImageHandle3}); |
| EXPECT_EQ(vsync_config_stamp_4, display::kInvalidDriverConfigStamp); |
| } |
| |
| } // namespace intel_display |