Skip to content

Commit

Permalink
gpu: win: Add support overlay 3D transform
Browse files Browse the repository at this point in the history
This CL adds support for non-flat transforms, which can happen in some
cases of delegated compositing. 4x4 matrices are both slightly less
performant and slightly less supported, so the 2D and 3D cases are kept
separate.

Change-Id: I74219137ab611dd17a647738bcb961690fffefb8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4717125
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: Rafael Cintron <rafael.cintron@microsoft.com>
Commit-Queue: Michael Tang <tangm@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1188609}
  • Loading branch information
tangm-msft authored and Chromium LUCI CQ committed Aug 26, 2023
1 parent aa4790f commit 8a15dd6
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 26 deletions.
73 changes: 47 additions & 26 deletions ui/gl/dc_layer_tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,43 @@ bool NeedSwapChainPresenter(const DCLayerOverlayParams* overlay) {
DCLayerOverlayType::kDCompVisualContent;
}

// Unconditionally get a IDCompositionVisual2 as a IDCompositionVisual3.
//
// |IDCompositionVisual3| should be available since Windows 8.1, but we noticed
// crashes due to unconditionally casting to the interface on the earliest
// versions of Windows 10. This should only be used for features that are
// conditionally run above those versions of Windows.
//
// See: https://crbug.com/1455666
Microsoft::WRL::ComPtr<IDCompositionVisual3> CheckedCastToVisual3(
const Microsoft::WRL::ComPtr<IDCompositionVisual2>& visual2) {
Microsoft::WRL::ComPtr<IDCompositionVisual3> visual3;
HRESULT hr = visual2.As(&visual3);
CHECK_EQ(hr, S_OK);
CHECK(visual3);
return visual3;
}

D2D_MATRIX_3X2_F TransformToD2D_MATRIX_3X2_F(const gfx::Transform& transform) {
DCHECK(transform.IsFlat());
// D2D_MATRIX_3x2_F is row-major.
DCHECK(transform.Is2dTransform());
// See |TransformToD2D_MATRIX_4X4_F| for notes.
return D2D1::Matrix3x2F(transform.rc(0, 0), transform.rc(1, 0),
transform.rc(0, 1), transform.rc(1, 1),
transform.rc(0, 3), transform.rc(1, 3));
}

D2D_MATRIX_4X4_F TransformToD2D_MATRIX_4X4_F(const gfx::Transform& transform) {
// D2D matrices are stored with the translation portion in the last row,
// whereas Skia matrices are stored with the translation in the last column.
// We need to transpose the matrix during the conversion to account for this
// difference.
const gfx::Transform& t = transform;
return D2D1::Matrix4x4F(t.rc(0, 0), t.rc(1, 0), t.rc(2, 0), t.rc(3, 0),
t.rc(0, 1), t.rc(1, 1), t.rc(2, 1), t.rc(3, 1),
t.rc(0, 2), t.rc(1, 2), t.rc(2, 2), t.rc(3, 2),
t.rc(0, 3), t.rc(1, 3), t.rc(2, 3), t.rc(3, 3));
}

// The size the surfaces in the pool. Used in |VisualSubtree::Update| to
// determine how to scale the background color visual. This can be any size
// since we need a non-empty surface to display the background fill, so 1x1
Expand Down Expand Up @@ -571,28 +600,16 @@ bool DCLayerTree::VisualTree::VisualSubtree::Update(
}

if (opacity_changed) {
// |IDCompositionVisual3| should be available since Windows 8.1, but we
// noticed crashes due to unconditionally casting to the interface on very
// early versions of Windows 10. Here, we only attempt the cast when the
// opacity changes, which should only happen for features that we don't
// intend to run unconditionally. If this cast fails, we may need to exclude
// some Windows versions from these features.
// See: https://crbug.com/1455666
Microsoft::WRL::ComPtr<IDCompositionVisual3> clip_visual_opacity;
hr = clip_visual_.As(&clip_visual_opacity);
CHECK_EQ(hr, S_OK);
CHECK(clip_visual_opacity);

if (opacity_ != 1) {
hr = clip_visual_opacity->SetOpacity(opacity_);
hr = CheckedCastToVisual3(clip_visual_)->SetOpacity(opacity_);
CHECK_EQ(hr, S_OK);

// Let all of this subtree's visuals blend as one, instead of
// individually
hr = clip_visual_->SetOpacityMode(DCOMPOSITION_OPACITY_MODE_LAYER);
CHECK_EQ(hr, S_OK);
} else {
hr = clip_visual_opacity->SetOpacity(1.0);
hr = CheckedCastToVisual3(clip_visual_)->SetOpacity(1.0);
CHECK_EQ(hr, S_OK);
hr = clip_visual_->SetOpacityMode(DCOMPOSITION_OPACITY_MODE_MULTIPLY);
CHECK_EQ(hr, S_OK);
Expand Down Expand Up @@ -661,11 +678,18 @@ bool DCLayerTree::VisualTree::VisualSubtree::Update(
}

if (quad_to_root_transform_changed) {
const D2D_MATRIX_3X2_F matrix =
TransformToD2D_MATRIX_3X2_F(quad_to_root_transform_);
hr = Microsoft::WRL::ComPtr<IDCompositionVisual>(transform_visual_)
->SetTransform(matrix);
CHECK_EQ(hr, S_OK);
if (quad_to_root_transform_.Is2dTransform()) {
const D2D_MATRIX_3X2_F matrix =
TransformToD2D_MATRIX_3X2_F(quad_to_root_transform_);
hr = Microsoft::WRL::ComPtr<IDCompositionVisual>(transform_visual_)
->SetTransform(matrix);
CHECK_EQ(hr, S_OK);
} else {
const D2D_MATRIX_4X4_F matrix =
TransformToD2D_MATRIX_4X4_F(quad_to_root_transform_);
hr = CheckedCastToVisual3(transform_visual_)->SetTransform(matrix);
CHECK_EQ(hr, S_OK);
}
}

if (nearest_neighbor_filter_changed) {
Expand Down Expand Up @@ -751,12 +775,9 @@ bool DCLayerTree::VisualTree::VisualSubtree::Update(
background_color_visual_->SetContent(background_color_surface_.Get());
CHECK_EQ(hr, S_OK);

Microsoft::WRL::ComPtr<IDCompositionVisual3>
background_color_visual_opacity;
hr = background_color_visual_.As(&background_color_visual_opacity);
hr = CheckedCastToVisual3(background_color_visual_)
->SetOpacity(background_color.fA);
CHECK_EQ(hr, S_OK);
CHECK(background_color_visual_opacity);
background_color_visual_opacity->SetOpacity(background_color.fA);
}
}

Expand Down
25 changes: 25 additions & 0 deletions ui/gl/dcomp_presenter_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1772,6 +1772,31 @@ TEST_F(DCompPresenterSkiaGoldTest, TransformRotation) {
PresentAndCheckScreenshot();
}

// Check that a complex transform (i.e. non-flat) works.
TEST_F(DCompPresenterSkiaGoldTest, Transform3D) {
InitializeTest(gfx::Size(100, 100));

InitializeRootAndScheduleRootSurface(current_window_size(), SkColors::kBlack);

auto overlay = std::make_unique<DCLayerOverlayParams>();

overlay->quad_rect = gfx::Rect(120, 75);

overlay->background_color = SkColors::kGreen;

overlay->z_order = 1;

overlay->transform.Translate(50, 50);
overlay->transform.ApplyPerspectiveDepth(100);
overlay->transform.RotateAboutYAxis(45);
overlay->transform.RotateAboutXAxis(30);
overlay->transform.Translate(-25, -25);

EXPECT_TRUE(presenter_->ScheduleDCLayer(std::move(overlay)));

PresentAndCheckScreenshot();
}

// This kind of transform is uncommon, but should be supported when rotations
// are supported.
TEST_F(DCompPresenterSkiaGoldTest, TransformShear) {
Expand Down

0 comments on commit 8a15dd6

Please sign in to comment.