/* * Copyright (C) 2019 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. */ #pragma once // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" #include #include #include #include #include #include #include "BufferGenerator.h" #include "utils/ScreenshotUtils.h" #include "utils/TransactionUtils.h" namespace android { using android::hardware::graphics::common::V1_1::BufferUsage; 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 sf(ComposerService::getComposerService()); ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed)); mCaptureArgs.displayToken = mDisplay; } virtual void TearDown() { mBlackBgSurface = 0; mClient->dispose(); mClient = 0; } virtual sp createLayer(const sp& client, const char* name, uint32_t width, uint32_t height, uint32_t flags = 0, SurfaceControl* parent = nullptr, uint32_t* outTransformHint = nullptr, PixelFormat format = PIXEL_FORMAT_RGBA_8888) { auto layer = createSurface(client, name, width, height, format, flags, parent, outTransformHint); 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 createSurface(const sp& client, const char* name, uint32_t width, uint32_t height, PixelFormat format, uint32_t flags, SurfaceControl* parent = nullptr, uint32_t* outTransformHint = nullptr) { sp parentHandle = (parent) ? parent->getHandle() : nullptr; auto layer = client->createSurface(String8(name), width, height, format, flags, parentHandle, LayerMetadata(), outTransformHint); EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl"; return layer; } virtual sp createLayer(const char* name, uint32_t width, uint32_t height, uint32_t flags = 0, SurfaceControl* parent = nullptr, uint32_t* outTransformHint = nullptr, PixelFormat format = PIXEL_FORMAT_RGBA_8888) { return createLayer(mClient, name, width, height, flags, parent, outTransformHint, format); } sp 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::eFXSurfaceEffect, 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& 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& layer) { ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost()); // wait for the newly posted buffer to be latched waitForLayerBuffers(); } virtual void fillBufferQueueLayerColor(const sp& layer, const Color& color, uint32_t bufferWidth, uint32_t bufferHeight) { ANativeWindow_Buffer buffer; ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color); postBufferQueueLayerBuffer(layer); } virtual void fillBufferStateLayerColor(const sp& layer, const Color& color, int32_t bufferWidth, int32_t bufferHeight) { sp buffer = new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE, "test"); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color); Transaction().setBuffer(layer, buffer).apply(); } void fillLayerColor(uint32_t mLayerType, const sp& layer, const Color& color, uint32_t bufferWidth, uint32_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& 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& 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; TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft); TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight); TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft); TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight); postBufferQueueLayerBuffer(layer); } virtual void fillBufferStateLayerQuadrant(const sp& layer, int32_t bufferWidth, int32_t bufferHeight, const Color& topLeft, const Color& topRight, const Color& bottomLeft, const Color& bottomRight) { sp buffer = new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE, "test"); ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0); const int32_t halfW = bufferWidth / 2; const int32_t halfH = bufferHeight / 2; TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft); TransactionUtils::fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight); TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft); TransactionUtils::fillGraphicBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight); Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply(); } std::unique_ptr screenshot() { std::unique_ptr screenshot; ScreenCapture::captureScreen(&screenshot); return screenshot; } void asTransaction(const std::function& exec) { Transaction t; exec(t); t.apply(true); } static status_t getBuffer(sp* outBuffer, sp* outFence) { static BufferGenerator bufferGenerator; return bufferGenerator.get(outBuffer, outFence); } static ui::Size getBufferSize() { static BufferGenerator bufferGenerator; return bufferGenerator.getSize(); } sp mClient; bool deviceSupportsBlurs() { char value[PROPERTY_VALUE_MAX]; property_get("ro.surface_flinger.supports_background_blur", value, "0"); return atoi(value); } bool deviceUsesSkiaRenderEngine() { char value[PROPERTY_VALUE_MAX]; property_get("debug.renderengine.backend", value, "default"); return strstr(value, "skia") != nullptr; } sp 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::max() - 256; sp mBlackBgSurface; bool mColorManagementUsed; DisplayCaptureArgs mCaptureArgs; ScreenCaptureResults mCaptureResults; private: void SetUpDisplay() { mDisplay = mClient->getInternalDisplayToken(); ASSERT_FALSE(mDisplay == nullptr) << "failed to get display"; ui::DisplayMode mode; ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(mDisplay, &mode)); mDisplayRect = Rect(mode.resolution); mDisplayWidth = mDisplayRect.getWidth(); mDisplayHeight = mDisplayRect.getHeight(); // 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 = static_cast(1e6 / mode.refreshRate) * 3; mDisplayLayerStack = 0; mBlackBgSurface = createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); // set layer stack (b/68888219) Transaction t; t.setDisplayLayerStack(mDisplay, mDisplayLayerStack); t.setCrop(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; }; } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"