| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <algorithm> |
| #include <chrono> |
| #include <cinttypes> |
| #include <functional> |
| #include <limits> |
| #include <ostream> |
| #include <thread> |
| |
| #include <gtest/gtest.h> |
| |
| #include <android/native_window.h> |
| |
| #include <binder/ProcessState.h> |
| #include <gui/BufferItemConsumer.h> |
| #include <gui/ISurfaceComposer.h> |
| #include <gui/LayerState.h> |
| #include <gui/Surface.h> |
| #include <gui/SurfaceComposerClient.h> |
| #include <hardware/hwcomposer_defs.h> |
| #include <private/android_filesystem_config.h> |
| #include <private/gui/ComposerService.h> |
| |
| #include <ui/ColorSpace.h> |
| #include <ui/DisplayInfo.h> |
| #include <ui/Rect.h> |
| #include <utils/String8.h> |
| |
| #include <math.h> |
| #include <math/vec3.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include "BufferGenerator.h" |
| |
| namespace android { |
| |
| namespace { |
| |
| struct Color { |
| uint8_t r; |
| uint8_t g; |
| uint8_t b; |
| uint8_t a; |
| |
| static const Color RED; |
| static const Color GREEN; |
| static const Color BLUE; |
| static const Color WHITE; |
| static const Color BLACK; |
| static const Color TRANSPARENT; |
| }; |
| |
| const Color Color::RED{255, 0, 0, 255}; |
| const Color Color::GREEN{0, 255, 0, 255}; |
| const Color Color::BLUE{0, 0, 255, 255}; |
| const Color Color::WHITE{255, 255, 255, 255}; |
| const Color Color::BLACK{0, 0, 0, 255}; |
| const Color Color::TRANSPARENT{0, 0, 0, 0}; |
| |
| using android::hardware::graphics::common::V1_1::BufferUsage; |
| using namespace std::chrono_literals; |
| |
| std::ostream& operator<<(std::ostream& os, const Color& color) { |
| os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a); |
| return os; |
| } |
| |
| // Fill a region with the specified color. |
| void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect, |
| const Color& color) { |
| Rect r(0, 0, buffer.width, buffer.height); |
| if (!r.intersect(rect, &r)) { |
| return; |
| } |
| |
| int32_t width = r.right - r.left; |
| int32_t height = r.bottom - r.top; |
| |
| for (int32_t row = 0; row < height; row++) { |
| uint8_t* dst = |
| static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (r.top + row) + r.left) * 4; |
| for (int32_t column = 0; column < width; column++) { |
| dst[0] = color.r; |
| dst[1] = color.g; |
| dst[2] = color.b; |
| dst[3] = color.a; |
| dst += 4; |
| } |
| } |
| } |
| |
| // Fill a region with the specified color. |
| void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect, const Color& color) { |
| Rect r(0, 0, buffer->width, buffer->height); |
| if (!r.intersect(rect, &r)) { |
| return; |
| } |
| |
| int32_t width = r.right - r.left; |
| int32_t height = r.bottom - r.top; |
| |
| uint8_t* pixels; |
| buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, |
| reinterpret_cast<void**>(&pixels)); |
| |
| for (int32_t row = 0; row < height; row++) { |
| uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4; |
| for (int32_t column = 0; column < width; column++) { |
| dst[0] = color.r; |
| dst[1] = color.g; |
| dst[2] = color.b; |
| dst[3] = color.a; |
| dst += 4; |
| } |
| } |
| buffer->unlock(); |
| } |
| |
| // Check if a region has the specified color. |
| void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels, const Rect& rect, |
| const Color& color, uint8_t tolerance) { |
| int32_t x = rect.left; |
| int32_t y = rect.top; |
| int32_t width = rect.right - rect.left; |
| int32_t height = rect.bottom - rect.top; |
| |
| int32_t bufferWidth = int32_t(outBuffer->getWidth()); |
| int32_t bufferHeight = int32_t(outBuffer->getHeight()); |
| if (x + width > bufferWidth) { |
| x = std::min(x, bufferWidth); |
| width = bufferWidth - x; |
| } |
| if (y + height > bufferHeight) { |
| y = std::min(y, bufferHeight); |
| height = bufferHeight - y; |
| } |
| |
| auto colorCompare = [tolerance](uint8_t a, uint8_t b) { |
| uint8_t tmp = a >= b ? a - b : b - a; |
| return tmp <= tolerance; |
| }; |
| for (int32_t j = 0; j < height; j++) { |
| const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4; |
| for (int32_t i = 0; i < width; i++) { |
| const uint8_t expected[4] = {color.r, color.g, color.b, color.a}; |
| EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare)) |
| << "pixel @ (" << x + i << ", " << y + j << "): " |
| << "expected (" << color << "), " |
| << "got (" << Color{src[0], src[1], src[2], src[3]} << ")"; |
| src += 4; |
| } |
| } |
| } |
| |
| } // anonymous namespace |
| |
| using Transaction = SurfaceComposerClient::Transaction; |
| |
| // Fill an RGBA_8888 formatted surface with a single color. |
| static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b, |
| bool unlock = true) { |
| ANativeWindow_Buffer outBuffer; |
| sp<Surface> s = sc->getSurface(); |
| ASSERT_TRUE(s != nullptr); |
| ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr)); |
| uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits); |
| for (int y = 0; y < outBuffer.height; y++) { |
| for (int x = 0; x < outBuffer.width; x++) { |
| uint8_t* pixel = img + (4 * (y * outBuffer.stride + x)); |
| pixel[0] = r; |
| pixel[1] = g; |
| pixel[2] = b; |
| pixel[3] = 255; |
| } |
| } |
| if (unlock) { |
| ASSERT_EQ(NO_ERROR, s->unlockAndPost()); |
| } |
| } |
| |
| // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check |
| // individual pixel values for testing purposes. |
| class ScreenCapture : public RefBase { |
| public: |
| static void captureScreen(std::unique_ptr<ScreenCapture>* sc) { |
| captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken()); |
| } |
| |
| static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) { |
| const auto sf = ComposerService::getComposerService(); |
| SurfaceComposerClient::Transaction().apply(true); |
| |
| sp<GraphicBuffer> outBuffer; |
| ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false)); |
| *sc = std::make_unique<ScreenCapture>(outBuffer); |
| } |
| |
| static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle, |
| Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) { |
| sp<ISurfaceComposer> sf(ComposerService::getComposerService()); |
| SurfaceComposerClient::Transaction().apply(true); |
| |
| sp<GraphicBuffer> outBuffer; |
| ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale)); |
| *sc = std::make_unique<ScreenCapture>(outBuffer); |
| } |
| |
| static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle, |
| Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) { |
| sp<ISurfaceComposer> sf(ComposerService::getComposerService()); |
| SurfaceComposerClient::Transaction().apply(true); |
| |
| sp<GraphicBuffer> outBuffer; |
| ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true)); |
| *sc = std::make_unique<ScreenCapture>(outBuffer); |
| } |
| |
| static void captureChildLayersExcluding( |
| std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle, |
| std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) { |
| sp<ISurfaceComposer> sf(ComposerService::getComposerService()); |
| SurfaceComposerClient::Transaction().apply(true); |
| |
| sp<GraphicBuffer> outBuffer; |
| ASSERT_EQ(NO_ERROR, |
| sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB, |
| ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers, |
| 1.0f, true)); |
| *sc = std::make_unique<ScreenCapture>(outBuffer); |
| } |
| |
| void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) { |
| ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); |
| expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance); |
| } |
| |
| void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) { |
| ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); |
| const bool leftBorder = rect.left > 0; |
| const bool topBorder = rect.top > 0; |
| const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth()); |
| const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight()); |
| |
| if (topBorder) { |
| Rect top(rect.left, rect.top - 1, rect.right, rect.top); |
| if (leftBorder) { |
| top.left -= 1; |
| } |
| if (rightBorder) { |
| top.right += 1; |
| } |
| expectColor(top, color, tolerance); |
| } |
| if (leftBorder) { |
| Rect left(rect.left - 1, rect.top, rect.left, rect.bottom); |
| expectColor(left, color, tolerance); |
| } |
| if (rightBorder) { |
| Rect right(rect.right, rect.top, rect.right + 1, rect.bottom); |
| expectColor(right, color, tolerance); |
| } |
| if (bottomBorder) { |
| Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1); |
| if (leftBorder) { |
| bottom.left -= 1; |
| } |
| if (rightBorder) { |
| bottom.right += 1; |
| } |
| expectColor(bottom, color, tolerance); |
| } |
| } |
| |
| void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight, |
| const Color& bottomLeft, const Color& bottomRight, bool filtered = false, |
| uint8_t tolerance = 0) { |
| ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0); |
| |
| const int32_t centerX = rect.left + (rect.right - rect.left) / 2; |
| const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2; |
| // avoid checking borders due to unspecified filtering behavior |
| const int32_t offsetX = filtered ? 2 : 0; |
| const int32_t offsetY = filtered ? 2 : 0; |
| expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft, |
| tolerance); |
| expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight, |
| tolerance); |
| expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft, |
| tolerance); |
| expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom), |
| bottomRight, tolerance); |
| } |
| |
| void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { |
| ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat()); |
| const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x)); |
| if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { |
| String8 err(String8::format("pixel @ (%3d, %3d): " |
| "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", |
| x, y, r, g, b, pixel[0], pixel[1], pixel[2])); |
| EXPECT_EQ(String8(), err) << err.string(); |
| } |
| } |
| |
| void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); } |
| |
| void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); } |
| |
| void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); } |
| |
| explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) { |
| mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels)); |
| } |
| |
| ~ScreenCapture() { mOutBuffer->unlock(); } |
| |
| private: |
| sp<GraphicBuffer> mOutBuffer; |
| uint8_t* mPixels = nullptr; |
| }; |
| |
| class LayerTransactionTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| mClient = new SurfaceComposerClient; |
| ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient"; |
| |
| ASSERT_NO_FATAL_FAILURE(SetUpDisplay()); |
| |
| sp<ISurfaceComposer> sf(ComposerService::getComposerService()); |
| ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed)); |
| } |
| |
| virtual void TearDown() { |
| mBlackBgSurface = 0; |
| mClient->dispose(); |
| mClient = 0; |
| } |
| |
| virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client, |
| const char* name, uint32_t width, uint32_t height, |
| uint32_t flags = 0, SurfaceControl* parent = nullptr) { |
| auto layer = |
| createSurface(client, name, width, height, PIXEL_FORMAT_RGBA_8888, flags, parent); |
| |
| Transaction t; |
| t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase); |
| |
| status_t error = t.apply(); |
| if (error != NO_ERROR) { |
| ADD_FAILURE() << "failed to initialize SurfaceControl"; |
| layer.clear(); |
| } |
| |
| return layer; |
| } |
| |
| virtual sp<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client, |
| const char* name, uint32_t width, uint32_t height, |
| PixelFormat format, uint32_t flags, |
| SurfaceControl* parent = nullptr) { |
| auto layer = client->createSurface(String8(name), width, height, format, flags, parent); |
| EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl"; |
| return layer; |
| } |
| |
| virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height, |
| uint32_t flags = 0, SurfaceControl* parent = nullptr) { |
| return createLayer(mClient, name, width, height, flags, parent); |
| } |
| |
| sp<SurfaceControl> createColorLayer(const char* name, const Color& color, |
| SurfaceControl* parent = nullptr) { |
| auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */, |
| PIXEL_FORMAT_RGBA_8888, |
| ISurfaceComposerClient::eFXSurfaceColor, parent); |
| asTransaction([&](Transaction& t) { |
| t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}); |
| t.setAlpha(colorLayer, color.a / 255.0f); |
| }); |
| return colorLayer; |
| } |
| |
| ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) { |
| // wait for previous transactions (such as setSize) to complete |
| Transaction().apply(true); |
| |
| ANativeWindow_Buffer buffer = {}; |
| EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr)); |
| |
| return buffer; |
| } |
| |
| void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) { |
| ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost()); |
| |
| // wait for the newly posted buffer to be latched |
| waitForLayerBuffers(); |
| } |
| |
| virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color, |
| int32_t bufferWidth, int32_t bufferHeight) { |
| ANativeWindow_Buffer buffer; |
| ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); |
| fillANativeWindowBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color); |
| postBufferQueueLayerBuffer(layer); |
| } |
| |
| virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color, |
| int32_t bufferWidth, int32_t bufferHeight) { |
| sp<GraphicBuffer> buffer = |
| new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1, |
| BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | |
| BufferUsage::COMPOSER_OVERLAY, |
| "test"); |
| fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color); |
| Transaction().setBuffer(layer, buffer).apply(); |
| } |
| |
| void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color, |
| int32_t bufferWidth, int32_t bufferHeight) { |
| switch (mLayerType) { |
| case ISurfaceComposerClient::eFXSurfaceBufferQueue: |
| fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight); |
| break; |
| case ISurfaceComposerClient::eFXSurfaceBufferState: |
| fillBufferStateLayerColor(layer, color, bufferWidth, bufferHeight); |
| break; |
| default: |
| ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType; |
| } |
| } |
| |
| void fillLayerQuadrant(uint32_t mLayerType, const sp<SurfaceControl>& layer, |
| int32_t bufferWidth, int32_t bufferHeight, const Color& topLeft, |
| const Color& topRight, const Color& bottomLeft, |
| const Color& bottomRight) { |
| switch (mLayerType) { |
| case ISurfaceComposerClient::eFXSurfaceBufferQueue: |
| fillBufferQueueLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight, |
| bottomLeft, bottomRight); |
| break; |
| case ISurfaceComposerClient::eFXSurfaceBufferState: |
| fillBufferStateLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight, |
| bottomLeft, bottomRight); |
| break; |
| default: |
| ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType; |
| } |
| } |
| |
| virtual void fillBufferQueueLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth, |
| int32_t bufferHeight, const Color& topLeft, |
| const Color& topRight, const Color& bottomLeft, |
| const Color& bottomRight) { |
| ANativeWindow_Buffer buffer; |
| ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); |
| ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0); |
| |
| const int32_t halfW = bufferWidth / 2; |
| const int32_t halfH = bufferHeight / 2; |
| fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft); |
| fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight); |
| fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft); |
| fillANativeWindowBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), |
| bottomRight); |
| |
| postBufferQueueLayerBuffer(layer); |
| } |
| |
| virtual void fillBufferStateLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth, |
| int32_t bufferHeight, const Color& topLeft, |
| const Color& topRight, const Color& bottomLeft, |
| const Color& bottomRight) { |
| sp<GraphicBuffer> buffer = |
| new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1, |
| BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | |
| BufferUsage::COMPOSER_OVERLAY, |
| "test"); |
| |
| ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0); |
| |
| const int32_t halfW = bufferWidth / 2; |
| const int32_t halfH = bufferHeight / 2; |
| fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft); |
| fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight); |
| fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft); |
| fillGraphicBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight); |
| |
| Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply(); |
| } |
| |
| std::unique_ptr<ScreenCapture> screenshot() { |
| std::unique_ptr<ScreenCapture> screenshot; |
| ScreenCapture::captureScreen(&screenshot); |
| return screenshot; |
| } |
| |
| void asTransaction(const std::function<void(Transaction&)>& exec) { |
| Transaction t; |
| exec(t); |
| t.apply(true); |
| } |
| |
| static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) { |
| static BufferGenerator bufferGenerator; |
| return bufferGenerator.get(outBuffer, outFence); |
| } |
| |
| sp<SurfaceComposerClient> mClient; |
| |
| sp<IBinder> mDisplay; |
| uint32_t mDisplayWidth; |
| uint32_t mDisplayHeight; |
| uint32_t mDisplayLayerStack; |
| Rect mDisplayRect = Rect::INVALID_RECT; |
| |
| // leave room for ~256 layers |
| const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256; |
| |
| sp<SurfaceControl> mBlackBgSurface; |
| bool mColorManagementUsed; |
| |
| private: |
| void SetUpDisplay() { |
| mDisplay = mClient->getInternalDisplayToken(); |
| ASSERT_FALSE(mDisplay == nullptr) << "failed to get display"; |
| |
| // get display width/height |
| DisplayInfo info; |
| ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info)); |
| mDisplayWidth = info.w; |
| mDisplayHeight = info.h; |
| mDisplayRect = |
| Rect(static_cast<int32_t>(mDisplayWidth), static_cast<int32_t>(mDisplayHeight)); |
| |
| // After a new buffer is queued, SurfaceFlinger is notified and will |
| // latch the new buffer on next vsync. Let's heuristically wait for 3 |
| // vsyncs. |
| mBufferPostDelay = int32_t(1e6 / info.fps) * 3; |
| |
| mDisplayLayerStack = 0; |
| |
| mBlackBgSurface = |
| createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */, |
| PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); |
| |
| // set layer stack (b/68888219) |
| Transaction t; |
| t.setDisplayLayerStack(mDisplay, mDisplayLayerStack); |
| t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight)); |
| t.setLayerStack(mBlackBgSurface, mDisplayLayerStack); |
| t.setColor(mBlackBgSurface, half3{0, 0, 0}); |
| t.setLayer(mBlackBgSurface, mLayerZBase); |
| t.apply(); |
| } |
| |
| void waitForLayerBuffers() { |
| // Request an empty transaction to get applied synchronously to ensure the buffer is |
| // latched. |
| Transaction().apply(true); |
| usleep(mBufferPostDelay); |
| } |
| |
| int32_t mBufferPostDelay; |
| |
| friend class LayerRenderPathTestHarness; |
| }; |
| enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY }; |
| |
| class LayerRenderPathTestHarness { |
| public: |
| LayerRenderPathTestHarness(LayerTransactionTest* delegate, RenderPath renderPath) |
| : mDelegate(delegate), mRenderPath(renderPath) {} |
| |
| std::unique_ptr<ScreenCapture> getScreenCapture() { |
| switch (mRenderPath) { |
| case RenderPath::SCREENSHOT: |
| return mDelegate->screenshot(); |
| case RenderPath::VIRTUAL_DISPLAY: |
| |
| const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken(); |
| DisplayInfo mainDisplayInfo; |
| SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo); |
| |
| sp<IBinder> vDisplay; |
| sp<IGraphicBufferProducer> producer; |
| sp<IGraphicBufferConsumer> consumer; |
| sp<BufferItemConsumer> itemConsumer; |
| BufferQueue::createBufferQueue(&producer, &consumer); |
| |
| consumer->setConsumerName(String8("Virtual disp consumer")); |
| consumer->setDefaultBufferSize(mainDisplayInfo.w, mainDisplayInfo.h); |
| |
| itemConsumer = new BufferItemConsumer(consumer, |
| // Sample usage bits from screenrecord |
| GRALLOC_USAGE_HW_VIDEO_ENCODER | |
| GRALLOC_USAGE_SW_READ_OFTEN); |
| |
| vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), |
| false /*secure*/); |
| |
| SurfaceComposerClient::Transaction t; |
| t.setDisplaySurface(vDisplay, producer); |
| t.setDisplayLayerStack(vDisplay, 0); |
| t.setDisplayProjection(vDisplay, mainDisplayInfo.orientation, |
| Rect(mainDisplayInfo.viewportW, mainDisplayInfo.viewportH), |
| Rect(mainDisplayInfo.w, mainDisplayInfo.h)); |
| t.apply(); |
| SurfaceComposerClient::Transaction().apply(true); |
| BufferItem item; |
| itemConsumer->acquireBuffer(&item, 0, true); |
| auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer); |
| itemConsumer->releaseBuffer(item); |
| SurfaceComposerClient::destroyDisplay(vDisplay); |
| return sc; |
| } |
| } |
| |
| protected: |
| LayerTransactionTest* mDelegate; |
| RenderPath mRenderPath; |
| }; |
| |
| class LayerTypeTransactionHarness : public LayerTransactionTest { |
| public: |
| LayerTypeTransactionHarness(uint32_t layerType) : mLayerType(layerType) {} |
| |
| sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height, |
| uint32_t flags = 0, SurfaceControl* parent = nullptr) { |
| // if the flags already have a layer type specified, return an error |
| if (flags & ISurfaceComposerClient::eFXSurfaceMask) { |
| return nullptr; |
| } |
| return LayerTransactionTest::createLayer(name, width, height, flags | mLayerType, parent); |
| } |
| |
| void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, int32_t bufferWidth, |
| int32_t bufferHeight) { |
| ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color, |
| bufferWidth, bufferHeight)); |
| } |
| |
| void fillLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth, |
| int32_t bufferHeight, const Color& topLeft, const Color& topRight, |
| const Color& bottomLeft, const Color& bottomRight) { |
| ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer, |
| bufferWidth, bufferHeight, |
| topLeft, topRight, |
| bottomLeft, bottomRight)); |
| } |
| |
| protected: |
| uint32_t mLayerType; |
| }; |
| |
| class LayerTypeTransactionTest : public LayerTypeTransactionHarness, |
| public ::testing::WithParamInterface<uint32_t> { |
| public: |
| LayerTypeTransactionTest() : LayerTypeTransactionHarness(GetParam()) {} |
| }; |
| |
| class LayerTypeAndRenderTypeTransactionTest |
| : public LayerTypeTransactionHarness, |
| public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> { |
| public: |
| LayerTypeAndRenderTypeTransactionTest() |
| : LayerTypeTransactionHarness(std::get<0>(GetParam())), |
| mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {} |
| |
| std::unique_ptr<ScreenCapture> getScreenCapture() { |
| return mRenderPathHarness.getScreenCapture(); |
| } |
| |
| protected: |
| LayerRenderPathTestHarness mRenderPathHarness; |
| }; |
| |
| // Environment for starting up binder threads. This is required for testing |
| // virtual displays, as BufferQueue parameters may be queried over binder. |
| class BinderEnvironment : public ::testing::Environment { |
| public: |
| void SetUp() override { ProcessState::self()->startThreadPool(); } |
| }; |
| |
| ::testing::Environment* const binderEnv = |
| ::testing::AddGlobalTestEnvironment(new BinderEnvironment()); |
| |
| class LayerRenderTypeTransactionTest : public LayerTransactionTest, |
| public ::testing::WithParamInterface<RenderPath> { |
| public: |
| LayerRenderTypeTransactionTest() : mHarness(LayerRenderPathTestHarness(this, GetParam())) {} |
| |
| std::unique_ptr<ScreenCapture> getScreenCapture() { return mHarness.getScreenCapture(); } |
| void setRelativeZBasicHelper(uint32_t layerType); |
| void setRelativeZGroupHelper(uint32_t layerType); |
| void setAlphaBasicHelper(uint32_t layerType); |
| void setBackgroundColorHelper(uint32_t layerType, bool priorColor, bool bufferFill, float alpha, |
| Color finalColor); |
| |
| protected: |
| LayerRenderPathTestHarness mHarness; |
| }; |
| |
| INSTANTIATE_TEST_CASE_P( |
| LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest, |
| ::testing::Combine( |
| ::testing::Values( |
| static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue), |
| static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)), |
| ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT))); |
| |
| INSTANTIATE_TEST_CASE_P(LayerRenderTypeTransactionTests, LayerRenderTypeTransactionTest, |
| ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)); |
| |
| INSTANTIATE_TEST_CASE_P( |
| LayerTypeTransactionTests, LayerTypeTransactionTest, |
| ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue), |
| static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState))); |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetPositionBasic_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| { |
| SCOPED_TRACE("default position"); |
| const Rect rect(0, 0, 32, 32); |
| auto shot = getScreenCapture(); |
| shot->expectColor(rect, Color::RED); |
| shot->expectBorder(rect, Color::BLACK); |
| } |
| |
| Transaction().setPosition(layer, 5, 10).apply(); |
| { |
| SCOPED_TRACE("new position"); |
| const Rect rect(5, 10, 37, 42); |
| auto shot = getScreenCapture(); |
| shot->expectColor(rect, Color::RED); |
| shot->expectBorder(rect, Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetPositionRounding_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // GLES requires only 4 bits of subpixel precision during rasterization |
| // XXX GLES composition does not match HWC composition due to precision |
| // loss (b/69315223) |
| const float epsilon = 1.0f / 16.0f; |
| Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply(); |
| { |
| SCOPED_TRACE("rounding down"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply(); |
| { |
| SCOPED_TRACE("rounding up"); |
| getScreenCapture()->expectColor(Rect(1, 1, 33, 33), Color::RED); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetPositionOutOfBounds_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| Transaction().setPosition(layer, -32, -32).apply(); |
| { |
| SCOPED_TRACE("negative coordinates"); |
| getScreenCapture()->expectColor(mDisplayRect, Color::BLACK); |
| } |
| |
| Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply(); |
| { |
| SCOPED_TRACE("positive coordinates"); |
| getScreenCapture()->expectColor(mDisplayRect, Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // partially out of bounds |
| Transaction().setPosition(layer, -30, -30).apply(); |
| { |
| SCOPED_TRACE("negative coordinates"); |
| getScreenCapture()->expectColor(Rect(0, 0, 2, 2), Color::RED); |
| } |
| |
| Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply(); |
| { |
| SCOPED_TRACE("positive coordinates"); |
| getScreenCapture()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth, |
| mDisplayHeight), |
| Color::RED); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // setPosition is applied immediately by default, with or without resize |
| // pending |
| Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply(); |
| { |
| SCOPED_TRACE("resize pending"); |
| auto shot = getScreenCapture(); |
| const Rect rect(5, 10, 37, 42); |
| shot->expectColor(rect, Color::RED); |
| shot->expectBorder(rect, Color::BLACK); |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); |
| { |
| SCOPED_TRACE("resize applied"); |
| getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResize_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // request setPosition to be applied with the next resize |
| Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply(); |
| { |
| SCOPED_TRACE("new position pending"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| Transaction().setPosition(layer, 15, 20).apply(); |
| { |
| SCOPED_TRACE("pending new position modified"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| Transaction().setSize(layer, 64, 64).apply(); |
| { |
| SCOPED_TRACE("resize pending"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| // finally resize and latch the buffer |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); |
| { |
| SCOPED_TRACE("new position applied"); |
| getScreenCapture()->expectColor(Rect(15, 20, 79, 84), Color::RED); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // setPosition is not immediate even with SCALE_TO_WINDOW override |
| Transaction() |
| .setPosition(layer, 5, 10) |
| .setSize(layer, 64, 64) |
| .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) |
| .setGeometryAppliesWithResize(layer) |
| .apply(); |
| { |
| SCOPED_TRACE("new position pending"); |
| getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED); |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); |
| { |
| SCOPED_TRACE("new position applied"); |
| getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| Transaction().setSize(layer, 64, 64).apply(); |
| { |
| SCOPED_TRACE("resize pending"); |
| auto shot = getScreenCapture(); |
| const Rect rect(0, 0, 32, 32); |
| shot->expectColor(rect, Color::RED); |
| shot->expectBorder(rect, Color::BLACK); |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); |
| { |
| SCOPED_TRACE("resize applied"); |
| auto shot = getScreenCapture(); |
| const Rect rect(0, 0, 64, 64); |
| shot->expectColor(rect, Color::RED); |
| shot->expectBorder(rect, Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) { |
| // cannot test robustness against invalid sizes (zero or really huge) |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition |
| Transaction() |
| .setSize(layer, 64, 64) |
| .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) |
| .apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED); |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) { |
| sp<SurfaceControl> layerR; |
| sp<SurfaceControl> layerG; |
| ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32)); |
| |
| Transaction().setLayer(layerR, mLayerZBase + 1).apply(); |
| { |
| SCOPED_TRACE("layerR"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| Transaction().setLayer(layerG, mLayerZBase + 2).apply(); |
| { |
| SCOPED_TRACE("layerG"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN); |
| } |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) { |
| sp<SurfaceControl> parent = |
| LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceContainer); |
| Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply(); |
| sp<SurfaceControl> layerR; |
| sp<SurfaceControl> layerG; |
| ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32)); |
| |
| Transaction() |
| .reparent(layerR, parent->getHandle()) |
| .reparent(layerG, parent->getHandle()) |
| .apply(); |
| Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply(); |
| { |
| SCOPED_TRACE("layerR"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| Transaction().setLayer(layerR, -3).apply(); |
| { |
| SCOPED_TRACE("layerG"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN); |
| } |
| } |
| |
| void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) { |
| sp<SurfaceControl> layerR; |
| sp<SurfaceControl> layerG; |
| ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32, layerType)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32)); |
| |
| switch (layerType) { |
| case ISurfaceComposerClient::eFXSurfaceBufferQueue: |
| Transaction() |
| .setPosition(layerG, 16, 16) |
| .setRelativeLayer(layerG, layerR->getHandle(), 1) |
| .apply(); |
| break; |
| case ISurfaceComposerClient::eFXSurfaceBufferState: |
| Transaction() |
| .setFrame(layerR, Rect(0, 0, 32, 32)) |
| .setFrame(layerG, Rect(16, 16, 48, 48)) |
| .setRelativeLayer(layerG, layerR->getHandle(), 1) |
| .apply(); |
| break; |
| default: |
| ASSERT_FALSE(true) << "Unsupported layer type"; |
| } |
| { |
| SCOPED_TRACE("layerG above"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 16, 16), Color::RED); |
| shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN); |
| } |
| |
| Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply(); |
| { |
| SCOPED_TRACE("layerG below"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferQueue) { |
| ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferState) { |
| ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState)); |
| } |
| |
| TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) { |
| sp<SurfaceControl> parent = |
| LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceContainer); |
| Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply(); |
| sp<SurfaceControl> layerR; |
| sp<SurfaceControl> layerG; |
| sp<SurfaceControl> layerB; |
| ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32)); |
| |
| Transaction() |
| .reparent(layerB, parent->getHandle()) |
| .apply(); |
| |
| // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2 |
| Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply(); |
| |
| std::unique_ptr<ScreenCapture> screenshot; |
| // only layerB is in this range |
| sp<IBinder> parentHandle = parent->getHandle(); |
| ScreenCapture::captureLayers(&screenshot, parentHandle, Rect(0, 0, 32, 32)); |
| screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); |
| } |
| |
| TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) { |
| sp<SurfaceControl> parent = |
| LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceColor); |
| |
| sp<SurfaceControl> childLayer; |
| ASSERT_NO_FATAL_FAILURE( |
| childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */, |
| 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceColor, |
| parent.get())); |
| Transaction() |
| .setColor(childLayer, half3{1.0f, 0.0f, 0.0f}) |
| .setColor(parent, half3{0.0f, 0.0f, 0.0f}) |
| .show(childLayer) |
| .show(parent) |
| .setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)) |
| .setCrop_legacy(childLayer, Rect(0, 0, 20, 30)) |
| .apply(); |
| |
| Transaction() |
| .setRelativeLayer(childLayer, parent->getHandle(), -1) |
| .setLayer(childLayer, 1) |
| .apply(); |
| |
| { |
| SCOPED_TRACE("setLayer above"); |
| // Set layer should get applied and place the child above. |
| std::unique_ptr<ScreenCapture> screenshot; |
| ScreenCapture::captureScreen(&screenshot); |
| screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED); |
| } |
| |
| Transaction() |
| .setLayer(childLayer, 1) |
| .setRelativeLayer(childLayer, parent->getHandle(), -1) |
| .apply(); |
| |
| { |
| SCOPED_TRACE("setRelative below"); |
| // Set relative layer should get applied and place the child below. |
| std::unique_ptr<ScreenCapture> screenshot; |
| ScreenCapture::captureScreen(&screenshot); |
| screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) { |
| sp<SurfaceControl> parent = |
| LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceColor); |
| sp<SurfaceControl> relativeParent = |
| LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */, |
| 0 /* buffer height */, ISurfaceComposerClient::eFXSurfaceColor); |
| |
| sp<SurfaceControl> childLayer; |
| ASSERT_NO_FATAL_FAILURE( |
| childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */, |
| 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceColor, |
| parent.get())); |
| Transaction() |
| .setColor(childLayer, half3{1.0f, 0.0f, 0.0f}) |
| .setColor(parent, half3{0.0f, 0.0f, 0.0f}) |
| .setColor(relativeParent, half3{0.0f, 1.0f, 0.0f}) |
| .show(childLayer) |
| .show(parent) |
| .show(relativeParent) |
| .setLayer(parent, mLayerZBase - 1) |
| .setLayer(relativeParent, mLayerZBase) |
| .apply(); |
| |
| Transaction() |
| .setRelativeLayer(childLayer, relativeParent->getHandle(), 1) |
| .apply(); |
| |
| { |
| SCOPED_TRACE("setLayer above"); |
| // Set layer should get applied and place the child above. |
| std::unique_ptr<ScreenCapture> screenshot; |
| ScreenCapture::captureScreen(&screenshot); |
| screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED); |
| } |
| |
| Transaction() |
| .hide(relativeParent) |
| .apply(); |
| |
| { |
| SCOPED_TRACE("hide relative parent"); |
| // The relative should no longer be visible. |
| std::unique_ptr<ScreenCapture> screenshot; |
| ScreenCapture::captureScreen(&screenshot); |
| screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK); |
| } |
| } |
| |
| void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) { |
| sp<SurfaceControl> layerR; |
| sp<SurfaceControl> layerG; |
| sp<SurfaceControl> layerB; |
| ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test", 32, 32, layerType)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test", 32, 32, layerType)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test", 32, 32, layerType)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerB, Color::BLUE, 32, 32)); |
| |
| // layerR = 0, layerG = layerR + 3, layerB = 2 |
| switch (layerType) { |
| case ISurfaceComposerClient::eFXSurfaceBufferQueue: |
| Transaction() |
| .setPosition(layerG, 8, 8) |
| .setRelativeLayer(layerG, layerR->getHandle(), 3) |
| .setPosition(layerB, 16, 16) |
| .setLayer(layerB, mLayerZBase + 2) |
| .apply(); |
| break; |
| case ISurfaceComposerClient::eFXSurfaceBufferState: |
| Transaction() |
| .setFrame(layerR, Rect(0, 0, 32, 32)) |
| .setFrame(layerG, Rect(8, 8, 40, 40)) |
| .setRelativeLayer(layerG, layerR->getHandle(), 3) |
| .setFrame(layerB, Rect(16, 16, 48, 48)) |
| .setLayer(layerB, mLayerZBase + 2) |
| .apply(); |
| break; |
| default: |
| ASSERT_FALSE(true) << "Unsupported layer type"; |
| } |
| |
| { |
| SCOPED_TRACE("(layerR < layerG) < layerB"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 8, 8), Color::RED); |
| shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN); |
| shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE); |
| } |
| |
| // layerR = 4, layerG = layerR + 3, layerB = 2 |
| Transaction().setLayer(layerR, mLayerZBase + 4).apply(); |
| { |
| SCOPED_TRACE("layerB < (layerR < layerG)"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 8, 8), Color::RED); |
| shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN); |
| shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE); |
| } |
| |
| // layerR = 4, layerG = layerR - 3, layerB = 2 |
| Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply(); |
| { |
| SCOPED_TRACE("layerB < (layerG < layerR)"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN); |
| shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE); |
| } |
| |
| // restore to absolute z |
| // layerR = 4, layerG = 0, layerB = 2 |
| Transaction().setLayer(layerG, mLayerZBase).apply(); |
| { |
| SCOPED_TRACE("layerG < layerB < layerR"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE); |
| } |
| |
| // layerR should not affect layerG anymore |
| // layerR = 1, layerG = 0, layerB = 2 |
| Transaction().setLayer(layerR, mLayerZBase + 1).apply(); |
| { |
| SCOPED_TRACE("layerG < layerR < layerB"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 16, 16), Color::RED); |
| shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferQueue) { |
| ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferState) { |
| ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState)); |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) { |
| sp<SurfaceControl> layerR; |
| sp<SurfaceControl> layerG; |
| |
| ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32)); |
| |
| Transaction() |
| .setPosition(layerG, 16, 16) |
| .setRelativeLayer(layerG, layerR->getHandle(), 1) |
| .apply(); |
| |
| layerG.clear(); |
| // layerG should have been removed |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32)); |
| |
| Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply(); |
| { |
| SCOPED_TRACE("layer hidden"); |
| getScreenCapture()->expectColor(mDisplayRect, Color::BLACK); |
| } |
| |
| Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply(); |
| { |
| SCOPED_TRACE("layer shown"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsOpaque) { |
| const Color translucentRed = {100, 0, 0, 100}; |
| sp<SurfaceControl> layerR; |
| sp<SurfaceControl> layerG; |
| ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32)); |
| |
| Transaction() |
| .setLayer(layerR, mLayerZBase + 1) |
| .setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque) |
| .apply(); |
| { |
| SCOPED_TRACE("layerR opaque"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255}); |
| } |
| |
| Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply(); |
| { |
| SCOPED_TRACE("layerR translucent"); |
| const uint8_t g = uint8_t(255 - translucentRed.a); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255}); |
| } |
| } |
| |
| TEST_P(LayerTypeTransactionTest, SetFlagsSecure) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32)); |
| |
| sp<ISurfaceComposer> composer = ComposerService::getComposerService(); |
| sp<GraphicBuffer> outBuffer; |
| Transaction() |
| .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure) |
| .apply(true); |
| ASSERT_EQ(PERMISSION_DENIED, |
| composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false)); |
| |
| Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true); |
| ASSERT_EQ(NO_ERROR, |
| composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false)); |
| } |
| |
| /** RAII Wrapper around get/seteuid */ |
| class UIDFaker { |
| uid_t oldId; |
| public: |
| UIDFaker(uid_t uid) { |
| oldId = geteuid(); |
| seteuid(uid); |
| } |
| ~UIDFaker() { |
| seteuid(oldId); |
| } |
| }; |
| |
| TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| sp<ISurfaceComposer> composer = ComposerService::getComposerService(); |
| sp<GraphicBuffer> outBuffer; |
| Transaction() |
| .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure) |
| .apply(true); |
| ASSERT_EQ(PERMISSION_DENIED, |
| composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false)); |
| |
| UIDFaker f(AID_SYSTEM); |
| |
| // By default the system can capture screenshots with secure layers but they |
| // will be blacked out |
| ASSERT_EQ(NO_ERROR, |
| composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false)); |
| |
| { |
| SCOPED_TRACE("as system"); |
| auto shot = screenshot(); |
| shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK); |
| } |
| |
| // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able |
| // to receive them...we are expected to take care with the results. |
| bool outCapturedSecureLayers; |
| ASSERT_EQ(NO_ERROR, |
| composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers, |
| ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0, |
| 0, false, ISurfaceComposer::eRotateNone, true)); |
| ASSERT_EQ(true, outCapturedSecureLayers); |
| ScreenCapture sc(outBuffer); |
| sc.expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) { |
| const Rect top(0, 0, 32, 16); |
| const Rect bottom(0, 16, 32, 32); |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| |
| ANativeWindow_Buffer buffer; |
| ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); |
| ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT)); |
| ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::RED)); |
| // setTransparentRegionHint always applies to the following buffer |
| Transaction().setTransparentRegionHint(layer, Region(top)).apply(); |
| ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer)); |
| { |
| SCOPED_TRACE("top transparent"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(top, Color::BLACK); |
| shot->expectColor(bottom, Color::RED); |
| } |
| |
| Transaction().setTransparentRegionHint(layer, Region(bottom)).apply(); |
| { |
| SCOPED_TRACE("transparent region hint pending"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(top, Color::BLACK); |
| shot->expectColor(bottom, Color::RED); |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); |
| ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::RED)); |
| ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT)); |
| ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer)); |
| { |
| SCOPED_TRACE("bottom transparent"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(top, Color::RED); |
| shot->expectColor(bottom, Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState) { |
| const Rect top(0, 0, 32, 16); |
| const Rect bottom(0, 16, 32, 32); |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE( |
| layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| |
| sp<GraphicBuffer> buffer = |
| new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, |
| BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | |
| BufferUsage::COMPOSER_OVERLAY, |
| "test"); |
| |
| ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::TRANSPARENT)); |
| ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::RED)); |
| Transaction() |
| .setTransparentRegionHint(layer, Region(top)) |
| .setBuffer(layer, buffer) |
| .setFrame(layer, Rect(0, 0, 32, 32)) |
| .apply(); |
| { |
| SCOPED_TRACE("top transparent"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(top, Color::BLACK); |
| shot->expectColor(bottom, Color::RED); |
| } |
| |
| Transaction().setTransparentRegionHint(layer, Region(bottom)).apply(); |
| { |
| SCOPED_TRACE("transparent region hint intermediate"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(top, Color::BLACK); |
| shot->expectColor(bottom, Color::BLACK); |
| } |
| |
| buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, |
| BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | |
| BufferUsage::COMPOSER_OVERLAY, |
| "test"); |
| |
| ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::RED)); |
| ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT)); |
| Transaction().setBuffer(layer, buffer).apply(); |
| { |
| SCOPED_TRACE("bottom transparent"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(top, Color::RED); |
| shot->expectColor(bottom, Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) { |
| sp<SurfaceControl> layerTransparent; |
| sp<SurfaceControl> layerR; |
| ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); |
| |
| // check that transparent region hint is bound by the layer size |
| Transaction() |
| .setTransparentRegionHint(layerTransparent, Region(mDisplayRect)) |
| .setPosition(layerR, 16, 16) |
| .setLayer(layerR, mLayerZBase + 1) |
| .apply(); |
| ASSERT_NO_FATAL_FAILURE( |
| fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32)); |
| getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) { |
| sp<SurfaceControl> layerTransparent; |
| sp<SurfaceControl> layerR; |
| ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE( |
| layerR = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| |
| // check that transparent region hint is bound by the layer size |
| Transaction() |
| .setTransparentRegionHint(layerTransparent, Region(mDisplayRect)) |
| .setFrame(layerR, Rect(16, 16, 48, 48)) |
| .setLayer(layerR, mLayerZBase + 1) |
| .apply(); |
| ASSERT_NO_FATAL_FAILURE( |
| fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32)); |
| getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED); |
| } |
| |
| void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) { |
| sp<SurfaceControl> layer1; |
| sp<SurfaceControl> layer2; |
| ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType)); |
| ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32, layerType)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer1, {64, 0, 0, 255}, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer2, {0, 64, 0, 255}, 32, 32)); |
| |
| switch (layerType) { |
| case ISurfaceComposerClient::eFXSurfaceBufferQueue: |
| Transaction() |
| .setAlpha(layer1, 0.25f) |
| .setAlpha(layer2, 0.75f) |
| .setPosition(layer2, 16, 0) |
| .setLayer(layer2, mLayerZBase + 1) |
| .apply(); |
| break; |
| case ISurfaceComposerClient::eFXSurfaceBufferState: |
| Transaction() |
| .setAlpha(layer1, 0.25f) |
| .setAlpha(layer2, 0.75f) |
| .setFrame(layer1, Rect(0, 0, 32, 32)) |
| .setFrame(layer2, Rect(16, 0, 48, 32)) |
| .setLayer(layer2, mLayerZBase + 1) |
| .apply(); |
| break; |
| default: |
| ASSERT_FALSE(true) << "Unsupported layer type"; |
| } |
| { |
| auto shot = getScreenCapture(); |
| uint8_t r = 16; // 64 * 0.25f |
| uint8_t g = 48; // 64 * 0.75f |
| shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255}); |
| shot->expectColor(Rect(32, 0, 48, 32), {0, g, 0, 255}); |
| |
| r /= 4; // r * (1.0f - 0.75f) |
| shot->expectColor(Rect(16, 0, 32, 32), {r, g, 0, 255}); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferQueue) { |
| ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferState) { |
| ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState)); |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetAlphaClamped) { |
| const Color color = {64, 0, 0, 255}; |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color, 32, 32)); |
| |
| Transaction().setAlpha(layer, 2.0f).apply(); |
| { |
| SCOPED_TRACE("clamped to 1.0f"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color); |
| } |
| |
| Transaction().setAlpha(layer, -1.0f).apply(); |
| { |
| SCOPED_TRACE("clamped to 0.0f"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) { |
| sp<SurfaceControl> layer; |
| const uint8_t size = 64; |
| const uint8_t testArea = 4; |
| const float cornerRadius = 20.0f; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size)); |
| |
| Transaction() |
| .setCornerRadius(layer, cornerRadius) |
| .apply(); |
| { |
| const uint8_t bottom = size - 1; |
| const uint8_t right = size - 1; |
| auto shot = getScreenCapture(); |
| // Transparent corners |
| shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK); |
| shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK); |
| shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK); |
| shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) { |
| sp<SurfaceControl> parent; |
| sp<SurfaceControl> child; |
| const uint8_t size = 64; |
| const uint8_t testArea = 4; |
| const float cornerRadius = 20.0f; |
| ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size)); |
| ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2)); |
| |
| Transaction() |
| .setCornerRadius(parent, cornerRadius) |
| .reparent(child, parent->getHandle()) |
| .setPosition(child, 0, size / 2) |
| .apply(); |
| { |
| const uint8_t bottom = size - 1; |
| const uint8_t right = size - 1; |
| auto shot = getScreenCapture(); |
| // Top edge of child should not have rounded corners because it's translated in the parent |
| shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)), |
| Color::GREEN); |
| // But bottom edges should have been clipped according to parent bounds |
| shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK); |
| shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) { |
| sp<SurfaceControl> bufferLayer; |
| sp<SurfaceControl> colorLayer; |
| ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(colorLayer = |
| createLayer("test", 0 /* buffer width */, 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceColor)); |
| |
| Transaction() |
| .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) |
| .setLayer(colorLayer, mLayerZBase + 1) |
| .apply(); |
| |
| { |
| SCOPED_TRACE("default color"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); |
| } |
| |
| const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); |
| const Color expected = {15, 51, 85, 255}; |
| // this is handwavy, but the precison loss scaled by 255 (8-bit per |
| // channel) should be less than one |
| const uint8_t tolerance = 1; |
| Transaction().setColor(colorLayer, color).apply(); |
| { |
| SCOPED_TRACE("new color"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expected, tolerance); |
| } |
| } |
| |
| // RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill |
| // BLUE: prior background color |
| // GREEN: final background color |
| // BLACK: no color or fill |
| void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType, bool priorColor, |
| bool bufferFill, float alpha, |
| Color finalColor) { |
| sp<SurfaceControl> layer; |
| int32_t width = 500; |
| int32_t height = 500; |
| |
| Color fillColor = Color::RED; |
| Color priorBgColor = Color::BLUE; |
| Color expectedColor = Color::BLACK; |
| switch (layerType) { |
| case ISurfaceComposerClient::eFXSurfaceColor: |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType)); |
| Transaction() |
| .setCrop_legacy(layer, Rect(0, 0, width, height)) |
| .setColor(layer, half3(1.0f, 0, 0)) |
| .apply(); |
| expectedColor = fillColor; |
| break; |
| case ISurfaceComposerClient::eFXSurfaceBufferQueue: |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height)); |
| if (bufferFill) { |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height)); |
| expectedColor = fillColor; |
| } |
| Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply(); |
| break; |
| case ISurfaceComposerClient::eFXSurfaceBufferState: |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType)); |
| if (bufferFill) { |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height)); |
| expectedColor = fillColor; |
| } |
| Transaction().setFrame(layer, Rect(0, 0, width, height)).apply(); |
| break; |
| default: |
| GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper"; |
| return; |
| } |
| |
| if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) { |
| Transaction() |
| .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN) |
| .apply(); |
| if (!bufferFill) { |
| expectedColor = priorBgColor; |
| } |
| } |
| |
| { |
| SCOPED_TRACE("default before setting background color layer"); |
| screenshot()->expectColor(Rect(0, 0, width, height), expectedColor); |
| } |
| Transaction() |
| .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN) |
| .apply(); |
| |
| { |
| auto shot = screenshot(); |
| shot->expectColor(Rect(0, 0, width, height), finalColor); |
| shot->expectBorder(Rect(0, 0, width, height), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) { |
| bool priorColor = false; |
| bool bufferFill = false; |
| float alpha = 1.0f; |
| Color finalColor = Color::RED; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) { |
| bool priorColor = false; |
| bool bufferFill = true; |
| float alpha = 1.0f; |
| Color finalColor = Color::RED; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) { |
| bool priorColor = false; |
| bool bufferFill = false; |
| float alpha = 1.0f; |
| Color finalColor = Color::GREEN; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) { |
| bool priorColor = true; |
| bool bufferFill = true; |
| float alpha = 1.0f; |
| Color finalColor = Color::RED; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) { |
| bool priorColor = true; |
| bool bufferFill = false; |
| float alpha = 1.0f; |
| Color finalColor = Color::GREEN; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) { |
| bool priorColor = false; |
| bool bufferFill = false; |
| float alpha = 0; |
| Color finalColor = Color::BLACK; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferQueue_PriorColor_ZeroAlpha_DeleteBackground) { |
| bool priorColor = true; |
| bool bufferFill = false; |
| float alpha = 0; |
| Color finalColor = Color::BLACK; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferState_BufferFill_NoPriorColor_Basic) { |
| bool priorColor = false; |
| bool bufferFill = true; |
| float alpha = 1.0f; |
| Color finalColor = Color::RED; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferState_NoBufferFill_NoPriorColor_Basic) { |
| bool priorColor = false; |
| bool bufferFill = false; |
| float alpha = 1.0f; |
| Color finalColor = Color::GREEN; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferState_NoBufferFill_PriorColor_Basic) { |
| bool priorColor = true; |
| bool bufferFill = false; |
| float alpha = 1.0f; |
| Color finalColor = Color::GREEN; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferState_NoPriorColor_ZeroAlpha_NoEffect) { |
| bool priorColor = false; |
| bool bufferFill = false; |
| float alpha = 0; |
| Color finalColor = Color::BLACK; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, |
| SetBackgroundColor_BufferState_PriorColor_ZeroAlpha_DeleteBackground) { |
| bool priorColor = true; |
| bool bufferFill = false; |
| float alpha = 0; |
| Color finalColor = Color::BLACK; |
| ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState, |
| priorColor, bufferFill, alpha, finalColor)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) { |
| sp<SurfaceControl> colorLayer; |
| ASSERT_NO_FATAL_FAILURE(colorLayer = |
| createLayer("test", 0 /* buffer width */, 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceColor)); |
| Transaction() |
| .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) |
| .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f)) |
| .apply(); |
| |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) { |
| sp<SurfaceControl> bufferLayer; |
| sp<SurfaceControl> colorLayer; |
| ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(colorLayer = |
| createLayer("test", 0 /* buffer width */, 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceColor)); |
| Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply(); |
| |
| const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); |
| const float alpha = 0.25f; |
| const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f); |
| // this is handwavy, but the precison loss scaled by 255 (8-bit per |
| // channel) should be less than one |
| const uint8_t tolerance = 1; |
| Transaction() |
| .setColor(colorLayer, color) |
| .setAlpha(colorLayer, alpha) |
| .setLayer(colorLayer, mLayerZBase + 1) |
| .apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255}, |
| tolerance); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) { |
| sp<SurfaceControl> bufferLayer; |
| sp<SurfaceControl> parentLayer; |
| sp<SurfaceControl> colorLayer; |
| ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */, |
| 0 /* buffer height */, |
| ISurfaceComposerClient::eFXSurfaceColor)); |
| Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply(); |
| const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); |
| const float alpha = 0.25f; |
| const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f); |
| // this is handwavy, but the precision loss scaled by 255 (8-bit per |
| // channel) should be less than one |
| const uint8_t tolerance = 1; |
| Transaction() |
| .reparent(colorLayer, parentLayer->getHandle()) |
| .setColor(colorLayer, color) |
| .setAlpha(parentLayer, alpha) |
| .setLayer(parentLayer, mLayerZBase + 1) |
| .apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255}, |
| tolerance); |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) { |
| sp<SurfaceControl> bufferLayer; |
| ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32)); |
| |
| // color is ignored |
| Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32)); |
| |
| Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply(); |
| { |
| SCOPED_TRACE("non-existing layer stack"); |
| getScreenCapture()->expectColor(mDisplayRect, Color::BLACK); |
| } |
| |
| Transaction().setLayerStack(layer, mDisplayLayerStack).apply(); |
| { |
| SCOPED_TRACE("original layer stack"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE)); |
| |
| Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply(); |
| { |
| SCOPED_TRACE("IDENTITY"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE); |
| } |
| |
| Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply(); |
| { |
| SCOPED_TRACE("FLIP_H"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, |
| Color::WHITE, Color::BLUE); |
| } |
| |
| Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply(); |
| { |
| SCOPED_TRACE("FLIP_V"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, |
| Color::RED, Color::GREEN); |
| } |
| |
| Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply(); |
| { |
| SCOPED_TRACE("ROT_90"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, |
| Color::WHITE, Color::GREEN); |
| } |
| |
| Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply(); |
| { |
| SCOPED_TRACE("SCALE"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE, true /* filtered */); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE( |
| layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE)); |
| |
| Transaction() |
| .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f) |
| .setFrame(layer, Rect(0, 0, 32, 32)) |
| .apply(); |
| { |
| SCOPED_TRACE("IDENTITY"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE); |
| } |
| |
| Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply(); |
| { |
| SCOPED_TRACE("FLIP_H"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE); |
| } |
| |
| Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply(); |
| { |
| SCOPED_TRACE("FLIP_V"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE); |
| } |
| |
| Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply(); |
| { |
| SCOPED_TRACE("ROT_90"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE); |
| } |
| |
| Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply(); |
| { |
| SCOPED_TRACE("SCALE"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE)); |
| |
| const float rot = M_SQRT1_2; // 45 degrees |
| const float trans = M_SQRT2 * 16.0f; |
| Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply(); |
| |
| auto shot = getScreenCapture(); |
| // check a 8x8 region inside each color |
| auto get8x8Rect = [](int32_t centerX, int32_t centerY) { |
| const int32_t halfL = 4; |
| return Rect(centerX - halfL, centerY - halfL, centerX + halfL, centerY + halfL); |
| }; |
| const int32_t unit = int32_t(trans / 2); |
| shot->expectColor(get8x8Rect(2 * unit, 1 * unit), Color::RED); |
| shot->expectColor(get8x8Rect(3 * unit, 2 * unit), Color::GREEN); |
| shot->expectColor(get8x8Rect(1 * unit, 2 * unit), Color::BLUE); |
| shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // setMatrix is applied after any pending resize, unlike setPosition |
| Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply(); |
| { |
| SCOPED_TRACE("resize pending"); |
| auto shot = getScreenCapture(); |
| const Rect rect(0, 0, 32, 32); |
| shot->expectColor(rect, Color::RED); |
| shot->expectBorder(rect, Color::BLACK); |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); |
| { |
| SCOPED_TRACE("resize applied"); |
| const Rect rect(0, 0, 128, 128); |
| getScreenCapture()->expectColor(rect, Color::RED); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition |
| Transaction() |
| .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f) |
| .setSize(layer, 64, 64) |
| .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) |
| .apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE)); |
| |
| // XXX SCALE_CROP is not respected; calling setSize and |
| // setOverrideScalingMode in separate transactions does not work |
| // (b/69315456) |
| Transaction() |
| .setSize(layer, 64, 16) |
| .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) |
| .apply(); |
| { |
| SCOPED_TRACE("SCALE_TO_WINDOW"); |
| getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN, |
| Color::BLUE, Color::WHITE, true /* filtered */); |
| } |
| } |
| |
| TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| |
| sp<IBinder> handle = layer->getHandle(); |
| ASSERT_TRUE(handle != nullptr); |
| |
| FrameStats frameStats; |
| mClient->getLayerFrameStats(handle, &frameStats); |
| |
| ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0)); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| const Rect crop(8, 8, 24, 24); |
| |
| Transaction().setCrop_legacy(layer, crop).apply(); |
| auto shot = getScreenCapture(); |
| shot->expectColor(crop, Color::RED); |
| shot->expectBorder(crop, Color::BLACK); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE( |
| layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); |
| const Rect crop(8, 8, 24, 24); |
| |
| Transaction().setCrop(layer, crop).apply(); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); |
| shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| { |
| SCOPED_TRACE("empty rect"); |
| Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| { |
| SCOPED_TRACE("negative rect"); |
| Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE( |
| layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); |
| |
| { |
| SCOPED_TRACE("empty rect"); |
| Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); |
| } |
| |
| { |
| SCOPED_TRACE("negative rect"); |
| Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply(); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE( |
| layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| sp<GraphicBuffer> buffer = |
| new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1, |
| BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | |
| BufferUsage::COMPOSER_OVERLAY, |
| "test"); |
| fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE); |
| fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED); |
| |
| Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply(); |
| |
| Transaction().setBuffer(layer, buffer).apply(); |
| |
| // Partially out of bounds in the negative (upper left) direction |
| Transaction().setCrop(layer, Rect(-128, -128, 32, 16)).apply(); |
| { |
| SCOPED_TRACE("out of bounds, negative (upper left) direction"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE); |
| shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); |
| } |
| |
| // Partially out of bounds in the positive (lower right) direction |
| Transaction().setCrop(layer, Rect(0, 16, 128, 128)).apply(); |
| { |
| SCOPED_TRACE("out of bounds, positive (lower right) direction"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 64, 64), Color::RED); |
| shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); |
| } |
| |
| // Fully out of buffer space bounds |
| Transaction().setCrop(layer, Rect(-128, -128, -1, -1)).apply(); |
| { |
| SCOPED_TRACE("Fully out of bounds"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE); |
| shot->expectColor(Rect(0, 16, 64, 64), Color::RED); |
| shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| const Point position(32, 32); |
| const Rect crop(8, 8, 24, 24); |
| Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply(); |
| auto shot = getScreenCapture(); |
| shot->expectColor(crop + position, Color::RED); |
| shot->expectBorder(crop + position, Color::BLACK); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE( |
| layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); |
| |
| const Rect frame(32, 32, 64, 64); |
| const Rect crop(8, 8, 24, 24); |
| Transaction().setFrame(layer, frame).setCrop(layer, crop).apply(); |
| auto shot = getScreenCapture(); |
| shot->expectColor(frame, Color::RED); |
| shot->expectBorder(frame, Color::BLACK); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // crop_legacy is affected by matrix |
| Transaction() |
| .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f) |
| .setCrop_legacy(layer, Rect(8, 8, 24, 24)) |
| .apply(); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(16, 16, 48, 48), Color::RED); |
| shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // setCrop_legacy is applied immediately by default, with or without resize pending |
| Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply(); |
| { |
| SCOPED_TRACE("resize pending"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(8, 8, 24, 24), Color::RED); |
| shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK); |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16)); |
| { |
| SCOPED_TRACE("resize applied"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(8, 8, 16, 16), Color::RED); |
| shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResize_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // request setCrop_legacy to be applied with the next resize |
| Transaction() |
| .setCrop_legacy(layer, Rect(8, 8, 24, 24)) |
| .setGeometryAppliesWithResize(layer) |
| .apply(); |
| { |
| SCOPED_TRACE("waiting for next resize"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply(); |
| { |
| SCOPED_TRACE("pending crop modified"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| Transaction().setSize(layer, 16, 16).apply(); |
| { |
| SCOPED_TRACE("resize pending"); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); |
| } |
| |
| // finally resize |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16)); |
| { |
| SCOPED_TRACE("new crop applied"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(4, 4, 12, 12), Color::RED); |
| shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); |
| |
| // setCrop_legacy is not immediate even with SCALE_TO_WINDOW override |
| Transaction() |
| .setCrop_legacy(layer, Rect(4, 4, 12, 12)) |
| .setSize(layer, 16, 16) |
| .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) |
| .setGeometryAppliesWithResize(layer) |
| .apply(); |
| { |
| SCOPED_TRACE("new crop pending"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 16, 16), Color::RED); |
| shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK); |
| } |
| |
| // XXX crop is never latched without other geometry change (b/69315677) |
| Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply(); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16)); |
| Transaction().setPosition(layer, 0, 0).apply(); |
| { |
| SCOPED_TRACE("new crop applied"); |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(4, 4, 12, 12), Color::RED); |
| shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE( |
| layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); |
| const Rect frame(8, 8, 24, 24); |
| |
| Transaction().setFrame(layer, frame).apply(); |
| auto shot = getScreenCapture(); |
| shot->expectColor(frame, Color::RED); |
| shot->expectBorder(frame, Color::BLACK); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE( |
| layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); |
| |
| { |
| SCOPED_TRACE("empty rect"); |
| Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); |
| } |
| |
| { |
| SCOPED_TRACE("negative rect"); |
| Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply(); |
| getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK); |
| } |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) { |
| sp<SurfaceControl> layer; |
| ASSERT_NO_FATAL_FAILURE( |
| layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10)); |
| |
| // A parentless layer will default to a frame with the same size as the buffer |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED); |
| shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) { |
| sp<SurfaceControl> parent, child; |
| ASSERT_NO_FATAL_FAILURE( |
| parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32)); |
| Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply(); |
| |
| ASSERT_NO_FATAL_FAILURE( |
| child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10)); |
| |
| Transaction().reparent(child, parent->getHandle()).apply(); |
| |
| // A layer will default to the frame of its parent |
| auto shot = getScreenCapture(); |
| shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); |
| shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); |
| } |
| |
| TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) { |
| sp<SurfaceControl> parent, child; |
| ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32)); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, |