| /* | 
 |  * 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 | 
 |  | 
 | #include <gtest/gtest.h> | 
 | #include <gui/ISurfaceComposer.h> | 
 | #include <gui/SurfaceComposerClient.h> | 
 | #include <private/gui/ComposerService.h> | 
 | #include <ui/DisplayConfig.h> | 
 |  | 
 | #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<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, | 
 |                                            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<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client, | 
 |                                              const char* name, uint32_t width, uint32_t height, | 
 |                                              PixelFormat format, uint32_t flags, | 
 |                                              SurfaceControl* parent = nullptr, | 
 |                                              uint32_t* outTransformHint = nullptr) { | 
 |         auto layer = client->createSurface(String8(name), width, height, format, flags, parent, | 
 |                                            LayerMetadata(), outTransformHint); | 
 |         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, | 
 |                                            uint32_t* outTransformHint = nullptr, | 
 |                                            PixelFormat format = PIXEL_FORMAT_RGBA_8888) { | 
 |         return createLayer(mClient, name, width, height, flags, parent, outTransformHint, format); | 
 |     } | 
 |  | 
 |     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::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<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)); | 
 |         TransactionUtils::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"); | 
 |         TransactionUtils::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; | 
 |         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<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; | 
 |         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<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"; | 
 |  | 
 |         DisplayConfig config; | 
 |         ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config)); | 
 |         mDisplayRect = Rect(config.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<int32_t>(1e6 / config.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_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; | 
 | }; | 
 |  | 
 | } // namespace android |