1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <android/gui/ISurfaceComposerClient.h>
18 #include <gtest/gtest.h>
19 #include <gui/DisplayCaptureArgs.h>
20 #include <ui/GraphicTypes.h>
21 #include <ui/Rect.h>
22
23 #include "LayerTransactionTest.h"
24
25 namespace android {
26
operator ==(const Color & left,const Color & right)27 bool operator==(const Color& left, const Color& right) {
28 return left.a == right.a && left.r == right.r && left.g == right.g && left.b == right.b;
29 }
30
31 class TextureFilteringTest : public LayerTransactionTest {
32 protected:
SetUp()33 virtual void SetUp() {
34 LayerTransactionTest::SetUp();
35
36 mParent = createLayer("test-parent", 100, 100,
37 gui::ISurfaceComposerClient::eFXSurfaceContainer);
38 mLayer = createLayer("test-child", 100, 100,
39 gui::ISurfaceComposerClient::eFXSurfaceBufferState, mParent.get());
40 sp<GraphicBuffer> buffer =
41 sp<GraphicBuffer>::make(static_cast<uint32_t>(100), static_cast<uint32_t>(100),
42 PIXEL_FORMAT_RGBA_8888, 1u,
43 BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
44 BufferUsage::COMPOSER_OVERLAY |
45 BufferUsage::GPU_TEXTURE,
46 "test");
47 TransactionUtils::fillGraphicBufferColor(buffer, Rect{0, 0, 50, 100}, Color::RED);
48 TransactionUtils::fillGraphicBufferColor(buffer, Rect{50, 0, 100, 100}, Color::BLUE);
49 Transaction()
50 .setBuffer(mLayer, buffer)
51 .setDataspace(mLayer, ui::Dataspace::V0_SRGB)
52 .setLayer(mLayer, INT32_MAX)
53 .apply();
54 }
55
TearDown()56 virtual void TearDown() { LayerTransactionTest::TearDown(); }
57
expectFiltered(Rect redRect,Rect blueRect)58 void expectFiltered(Rect redRect, Rect blueRect) {
59 // Check that at least some of the pixels in the red rectangle aren't solid red
60 int redPixels = 0;
61 for (int x = redRect.left; x < redRect.right; x++) {
62 for (int y = redRect.top; y < redRect.bottom; y++) {
63 redPixels += mCapture->getPixelColor(static_cast<uint32_t>(x),
64 static_cast<uint32_t>(y)) == Color::RED;
65 }
66 }
67 ASSERT_LT(redPixels, redRect.getWidth() * redRect.getHeight());
68
69 // Check that at least some of the pixels in the blue rectangle aren't solid blue
70 int bluePixels = 0;
71 for (int x = blueRect.left; x < blueRect.right; x++) {
72 for (int y = blueRect.top; y < blueRect.bottom; y++) {
73 bluePixels += mCapture->getPixelColor(static_cast<uint32_t>(x),
74 static_cast<uint32_t>(y)) == Color::BLUE;
75 }
76 }
77 ASSERT_LT(bluePixels, blueRect.getWidth() * blueRect.getHeight());
78 }
79
80 sp<SurfaceControl> mParent;
81 sp<SurfaceControl> mLayer;
82 std::unique_ptr<ScreenCapture> mCapture;
83 };
84
TEST_F(TextureFilteringTest,NoFiltering)85 TEST_F(TextureFilteringTest, NoFiltering) {
86 gui::DisplayCaptureArgs captureArgs;
87 captureArgs.displayToken = mDisplay;
88 captureArgs.width = 100;
89 captureArgs.height = 100;
90 captureArgs.sourceCrop = Rect{100, 100};
91 ScreenCapture::captureDisplay(&mCapture, captureArgs);
92
93 mCapture->expectColor(Rect{0, 0, 50, 100}, Color::RED);
94 mCapture->expectColor(Rect{50, 0, 100, 100}, Color::BLUE);
95 }
96
TEST_F(TextureFilteringTest,BufferCropNoFiltering)97 TEST_F(TextureFilteringTest, BufferCropNoFiltering) {
98 Transaction().setBufferCrop(mLayer, Rect{0, 0, 100, 100}).apply();
99
100 gui::DisplayCaptureArgs captureArgs;
101 captureArgs.displayToken = mDisplay;
102 captureArgs.width = 100;
103 captureArgs.height = 100;
104 captureArgs.sourceCrop = Rect{0, 0, 100, 100};
105 ScreenCapture::captureDisplay(&mCapture, captureArgs);
106
107 mCapture->expectColor(Rect{0, 0, 50, 100}, Color::RED);
108 mCapture->expectColor(Rect{50, 0, 100, 100}, Color::BLUE);
109 }
110
111 // Expect filtering because the buffer is stretched to the layer's bounds.
TEST_F(TextureFilteringTest,BufferCropIsFiltered)112 TEST_F(TextureFilteringTest, BufferCropIsFiltered) {
113 Transaction().setBufferCrop(mLayer, Rect{25, 25, 75, 75}).apply();
114
115 gui::DisplayCaptureArgs captureArgs;
116 captureArgs.displayToken = mDisplay;
117 captureArgs.width = 100;
118 captureArgs.height = 100;
119 captureArgs.sourceCrop = Rect{0, 0, 100, 100};
120 ScreenCapture::captureDisplay(&mCapture, captureArgs);
121
122 expectFiltered({0, 0, 50, 100}, {50, 0, 100, 100});
123 }
124
125 // Expect filtering because the output source crop is stretched to the output buffer's size.
TEST_F(TextureFilteringTest,OutputSourceCropIsFiltered)126 TEST_F(TextureFilteringTest, OutputSourceCropIsFiltered) {
127 gui::DisplayCaptureArgs captureArgs;
128 captureArgs.displayToken = mDisplay;
129 captureArgs.width = 100;
130 captureArgs.height = 100;
131 captureArgs.sourceCrop = Rect{25, 25, 75, 75};
132 ScreenCapture::captureDisplay(&mCapture, captureArgs);
133
134 expectFiltered({0, 0, 50, 100}, {50, 0, 100, 100});
135 }
136
137 // Expect filtering because the layer crop and output source crop are stretched to the output
138 // buffer's size.
TEST_F(TextureFilteringTest,LayerCropOutputSourceCropIsFiltered)139 TEST_F(TextureFilteringTest, LayerCropOutputSourceCropIsFiltered) {
140 Transaction().setCrop(mLayer, Rect{25, 25, 75, 75}).apply();
141
142 gui::DisplayCaptureArgs captureArgs;
143 captureArgs.displayToken = mDisplay;
144 captureArgs.width = 100;
145 captureArgs.height = 100;
146 captureArgs.sourceCrop = Rect{25, 25, 75, 75};
147 ScreenCapture::captureDisplay(&mCapture, captureArgs);
148
149 expectFiltered({0, 0, 50, 100}, {50, 0, 100, 100});
150 }
151
152 // Expect filtering because the layer is scaled up.
TEST_F(TextureFilteringTest,LayerCaptureWithScalingIsFiltered)153 TEST_F(TextureFilteringTest, LayerCaptureWithScalingIsFiltered) {
154 LayerCaptureArgs captureArgs;
155 captureArgs.layerHandle = mLayer->getHandle();
156 captureArgs.frameScaleX = 2;
157 captureArgs.frameScaleY = 2;
158 ScreenCapture::captureLayers(&mCapture, captureArgs);
159
160 expectFiltered({0, 0, 100, 200}, {100, 0, 200, 200});
161 }
162
163 // Expect no filtering because the output buffer's size matches the source crop.
TEST_F(TextureFilteringTest,LayerCaptureOutputSourceCropNoFiltering)164 TEST_F(TextureFilteringTest, LayerCaptureOutputSourceCropNoFiltering) {
165 LayerCaptureArgs captureArgs;
166 captureArgs.layerHandle = mLayer->getHandle();
167 captureArgs.sourceCrop = Rect{25, 25, 75, 75};
168 ScreenCapture::captureLayers(&mCapture, captureArgs);
169
170 mCapture->expectColor(Rect{0, 0, 25, 50}, Color::RED);
171 mCapture->expectColor(Rect{25, 0, 50, 50}, Color::BLUE);
172 }
173
174 // Expect no filtering because the output buffer's size matches the source crop (with a cropped
175 // layer).
TEST_F(TextureFilteringTest,LayerCaptureWithCropNoFiltering)176 TEST_F(TextureFilteringTest, LayerCaptureWithCropNoFiltering) {
177 Transaction().setCrop(mLayer, Rect{10, 10, 90, 90}).apply();
178
179 LayerCaptureArgs captureArgs;
180 captureArgs.layerHandle = mLayer->getHandle();
181 captureArgs.sourceCrop = Rect{25, 25, 75, 75};
182 ScreenCapture::captureLayers(&mCapture, captureArgs);
183
184 mCapture->expectColor(Rect{0, 0, 25, 50}, Color::RED);
185 mCapture->expectColor(Rect{25, 0, 50, 50}, Color::BLUE);
186 }
187
188 // Expect no filtering because the output source crop and output buffer are the same size.
TEST_F(TextureFilteringTest,OutputSourceCropDisplayFrameMatchNoFiltering)189 TEST_F(TextureFilteringTest, OutputSourceCropDisplayFrameMatchNoFiltering) {
190 gui::DisplayCaptureArgs captureArgs;
191 captureArgs.displayToken = mDisplay;
192 captureArgs.width = 50;
193 captureArgs.height = 50;
194 captureArgs.sourceCrop = Rect{25, 25, 75, 75};
195 ScreenCapture::captureDisplay(&mCapture, captureArgs);
196
197 mCapture->expectColor(Rect{0, 0, 25, 50}, Color::RED);
198 mCapture->expectColor(Rect{25, 0, 50, 50}, Color::BLUE);
199 }
200
201 // Expect no filtering because the layer crop shouldn't scale the layer.
TEST_F(TextureFilteringTest,LayerCropDisplayFrameMatchNoFiltering)202 TEST_F(TextureFilteringTest, LayerCropDisplayFrameMatchNoFiltering) {
203 Transaction().setCrop(mLayer, Rect{25, 25, 75, 75}).apply();
204
205 gui::DisplayCaptureArgs captureArgs;
206 captureArgs.displayToken = mDisplay;
207 ScreenCapture::captureDisplay(&mCapture, captureArgs);
208
209 mCapture->expectColor(Rect{25, 25, 50, 75}, Color::RED);
210 mCapture->expectColor(Rect{50, 25, 75, 75}, Color::BLUE);
211 }
212
213 // Expect no filtering because the parent layer crop shouldn't scale the layer.
TEST_F(TextureFilteringTest,ParentCropNoFiltering)214 TEST_F(TextureFilteringTest, ParentCropNoFiltering) {
215 Transaction().setCrop(mParent, Rect{25, 25, 75, 75}).apply();
216
217 gui::DisplayCaptureArgs captureArgs;
218 captureArgs.displayToken = mDisplay;
219 ScreenCapture::captureDisplay(&mCapture, captureArgs);
220
221 mCapture->expectColor(Rect{25, 25, 50, 75}, Color::RED);
222 mCapture->expectColor(Rect{50, 25, 75, 75}, Color::BLUE);
223 }
224
225 // Expect no filtering because parent's position transform shouldn't scale the layer.
TEST_F(TextureFilteringTest,ParentHasTransformNoFiltering)226 TEST_F(TextureFilteringTest, ParentHasTransformNoFiltering) {
227 Transaction().setPosition(mParent, 100, 100).apply();
228
229 LayerCaptureArgs captureArgs;
230 captureArgs.layerHandle = mParent->getHandle();
231 captureArgs.sourceCrop = Rect{0, 0, 100, 100};
232 ScreenCapture::captureLayers(&mCapture, captureArgs);
233
234 mCapture->expectColor(Rect{0, 0, 50, 100}, Color::RED);
235 mCapture->expectColor(Rect{50, 0, 100, 100}, Color::BLUE);
236 }
237
238 } // namespace android
239