diff options
| author | 2017-03-13 17:50:25 +0000 | |
|---|---|---|
| committer | 2017-03-13 17:50:26 +0000 | |
| commit | 29943c197182e7c48997dd974a22662fedea9bec (patch) | |
| tree | d8c265035effbb5763eea580f646907bbc7bbda1 | |
| parent | 42f482e1391d4bf247a9a63cad2178bcaf84080a (diff) | |
| parent | ae7d324fcad6d561bc0ee460f296ff2ad8306b00 (diff) | |
Merge changes from topic 'test-hwc2'
* changes:
test-hwc2: dump
test-hwc2: virtual displays
test-hwc2: color and hdr requests
test-hwc2: present display
test-hwc2: add client target support
test-hwc2: get and accept display changes
test-hwc2: validate display
test-hwc2: set layer visible region
test-hwc2: set layer buffer
test-hwc2: set layer surface damage
test-hwc2: set cursor position
test-hwc2: set layer color
test-hwc2: set layer source crop
test-hwc2: set layer display frame
test-hwc2: set layer z order
test-hwc2: set layer transform
test-hwc2: set layer plane alpha
test-hwc2: set layer dataspace
test-hwc2: set layer blend mode
test-hwc2: set layer composition type
test-hwc2: get display name
test-hwc2: enable vsync
test-hwc2: power mode support
test-hwc2: get and set active config
test-hwc2: get display configs and attributes
test-hwc2: create and destroy layers
test-hwc2: display type support
test-hwc2: register callback functions
test-hwc2: open and close hwc2 device
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Android.mk | 53 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2Test.cpp | 4556 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp | 692 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h | 77 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp | 102 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h | 69 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp | 249 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h | 103 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp | 281 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h | 86 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp | 782 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h | 384 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp | 61 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h | 49 |
14 files changed, 7544 insertions, 0 deletions
diff --git a/services/surfaceflinger/tests/hwc2/Android.mk b/services/surfaceflinger/tests/hwc2/Android.mk new file mode 100644 index 0000000000..b8c2133027 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Android.mk @@ -0,0 +1,53 @@ +# +# Copyright (C) 2016 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := test-hwc2 +LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS += \ + -fstack-protector-all \ + -g \ + -Wall -Wextra \ + -Werror \ + -fno-builtin \ + -DEGL_EGLEXT_PROTOTYPES \ + -DGL_GLEXT_PROTOTYPES +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libhardware \ + libEGL \ + libGLESv2 \ + libui \ + libgui \ + liblog \ + libsync +LOCAL_STATIC_LIBRARIES := \ + libbase \ + libadf \ + libadfhwc +LOCAL_SRC_FILES := \ + Hwc2Test.cpp \ + Hwc2TestProperties.cpp \ + Hwc2TestLayer.cpp \ + Hwc2TestLayers.cpp \ + Hwc2TestBuffer.cpp \ + Hwc2TestClientTarget.cpp \ + Hwc2TestVirtualDisplay.cpp + +include $(BUILD_NATIVE_TEST) diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp new file mode 100644 index 0000000000..062485ea52 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp @@ -0,0 +1,4556 @@ +/* + * Copyright (C) 2016 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 <array> +#include <unordered_set> +#include <unordered_map> +#include <gtest/gtest.h> +#include <dlfcn.h> +#include <android-base/unique_fd.h> +#include <hardware/hardware.h> +#include <sync/sync.h> + +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + +#include "Hwc2TestLayer.h" +#include "Hwc2TestLayers.h" +#include "Hwc2TestClientTarget.h" +#include "Hwc2TestVirtualDisplay.h" + +void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData, + hwc2_display_t display, int32_t connected); +void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData, + hwc2_display_t display, int64_t timestamp); + +class Hwc2Test : public testing::Test { +public: + + virtual void SetUp() + { + hw_module_t const* hwc2Module; + + int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwc2Module); + ASSERT_GE(err, 0) << "failed to get hwc hardware module: " + << strerror(-err); + + /* The following method will fail if you have not run + * "adb shell stop" */ + err = hwc2_open(hwc2Module, &mHwc2Device); + ASSERT_GE(err, 0) << "failed to open hwc hardware module: " + << strerror(-err); + + populateDisplays(); + } + + virtual void TearDown() + { + + for (auto itr = mLayers.begin(); itr != mLayers.end();) { + hwc2_display_t display = itr->first; + hwc2_layer_t layer = itr->second; + itr++; + /* Destroys and removes the layer from mLayers */ + destroyLayer(display, layer); + } + + for (auto itr = mActiveDisplays.begin(); itr != mActiveDisplays.end();) { + hwc2_display_t display = *itr; + itr++; + /* Sets power mode to off and removes the display from + * mActiveDisplays */ + setPowerMode(display, HWC2_POWER_MODE_OFF); + } + + for (auto itr = mVirtualDisplays.begin(); itr != mVirtualDisplays.end();) { + hwc2_display_t display = *itr; + itr++; + /* Destroys virtual displays */ + destroyVirtualDisplay(display); + } + + if (mHwc2Device) + hwc2_close(mHwc2Device); + } + + void registerCallback(hwc2_callback_descriptor_t descriptor, + hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_REGISTER_CALLBACK>( + getFunction(HWC2_FUNCTION_REGISTER_CALLBACK)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, descriptor, + callbackData, pointer)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to register callback"; + } + } + + void getDisplayType(hwc2_display_t display, hwc2_display_type_t* outType, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_TYPE>( + getFunction(HWC2_FUNCTION_GET_DISPLAY_TYPE)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + reinterpret_cast<int32_t*>(outType))); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display type"; + } + } + + /* If the populateDisplays function is still receiving displays and the + * display is connected, the display handle is stored in mDisplays. */ + void hotplugCallback(hwc2_display_t display, int32_t connected) + { + std::lock_guard<std::mutex> lock(mHotplugMutex); + + if (mHotplugStatus != Hwc2TestHotplugStatus::Receiving) + return; + + if (connected == HWC2_CONNECTION_CONNECTED) + mDisplays.insert(display); + + mHotplugCv.notify_all(); + } + + void createLayer(hwc2_display_t display, hwc2_layer_t* outLayer, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_CREATE_LAYER>( + getFunction(HWC2_FUNCTION_CREATE_LAYER)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + outLayer)); + + if (err == HWC2_ERROR_NONE) + mLayers.insert(std::make_pair(display, *outLayer)); + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create layer"; + } + } + + void destroyLayer(hwc2_display_t display, hwc2_layer_t layer, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_DESTROY_LAYER>( + getFunction(HWC2_FUNCTION_DESTROY_LAYER)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer)); + + if (err == HWC2_ERROR_NONE) + mLayers.erase(std::make_pair(display, layer)); + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to destroy layer " + << layer; + } + } + + void getDisplayAttribute(hwc2_display_t display, hwc2_config_t config, + hwc2_attribute_t attribute, int32_t* outValue, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>( + getFunction(HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, config, + attribute, outValue)); + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display attribute " + << getAttributeName(attribute) << " for config " << config; + } + } + + void getDisplayConfigs(hwc2_display_t display, + std::vector<hwc2_config_t>* outConfigs, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_CONFIGS>( + getFunction(HWC2_FUNCTION_GET_DISPLAY_CONFIGS)); + ASSERT_TRUE(pfn) << "failed to get function"; + + uint32_t numConfigs = 0; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + &numConfigs, nullptr)); + + if (err == HWC2_ERROR_NONE) { + outConfigs->resize(numConfigs); + + err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + &numConfigs, outConfigs->data())); + } + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get configs for" + " display " << display; + } + } + + void getActiveConfig(hwc2_display_t display, hwc2_config_t* outConfig, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_ACTIVE_CONFIG>( + getFunction(HWC2_FUNCTION_GET_ACTIVE_CONFIG)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + outConfig)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get active config on" + " display " << display; + } + } + + void setActiveConfig(hwc2_display_t display, hwc2_config_t config, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_ACTIVE_CONFIG>( + getFunction(HWC2_FUNCTION_SET_ACTIVE_CONFIG)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, config)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set active config " + << config; + } + } + + void getDozeSupport(hwc2_display_t display, int32_t* outSupport, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_DOZE_SUPPORT>( + getFunction(HWC2_FUNCTION_GET_DOZE_SUPPORT)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + outSupport)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get doze support on" + " display " << display; + } + } + + void setPowerMode(hwc2_display_t display, hwc2_power_mode_t mode, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_POWER_MODE>( + getFunction(HWC2_FUNCTION_SET_POWER_MODE)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + mode)); + if (outErr) { + *outErr = err; + if (err != HWC2_ERROR_NONE) + return; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set power mode " + << getPowerModeName(mode) << " on display " << display; + } + + if (mode == HWC2_POWER_MODE_OFF) { + mActiveDisplays.erase(display); + } else { + mActiveDisplays.insert(display); + } + } + + void setVsyncEnabled(hwc2_display_t display, hwc2_vsync_t enabled, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_VSYNC_ENABLED>( + getFunction(HWC2_FUNCTION_SET_VSYNC_ENABLED)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + enabled)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set vsync enabled " + << getVsyncName(enabled); + } + } + + void vsyncCallback(hwc2_display_t display, int64_t timestamp) + { + std::lock_guard<std::mutex> lock(mVsyncMutex); + mVsyncDisplay = display; + mVsyncTimestamp = timestamp; + mVsyncCv.notify_all(); + } + + void getDisplayName(hwc2_display_t display, std::string* outName, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_NAME>( + getFunction(HWC2_FUNCTION_GET_DISPLAY_NAME)); + ASSERT_TRUE(pfn) << "failed to get function"; + + uint32_t size = 0; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &size, + nullptr)); + + if (err == HWC2_ERROR_NONE) { + std::vector<char> name(size); + + err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &size, + name.data())); + + outName->assign(name.data()); + } + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display name for " + << display; + } + } + + void setLayerCompositionType(hwc2_display_t display, hwc2_layer_t layer, + hwc2_composition_t composition, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>( + getFunction(HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + composition)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer composition" + " type " << getCompositionName(composition); + } + } + + void setCursorPosition(hwc2_display_t display, hwc2_layer_t layer, + int32_t x, int32_t y, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_CURSOR_POSITION>( + getFunction(HWC2_FUNCTION_SET_CURSOR_POSITION)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, x, + y)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set cursor position"; + } + } + + void setLayerBlendMode(hwc2_display_t display, hwc2_layer_t layer, + hwc2_blend_mode_t mode, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_BLEND_MODE>( + getFunction(HWC2_FUNCTION_SET_LAYER_BLEND_MODE)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + mode)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer blend mode " + << getBlendModeName(mode); + } + } + + void setLayerBuffer(hwc2_display_t display, hwc2_layer_t layer, + buffer_handle_t buffer, int32_t acquireFence, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_BUFFER>( + getFunction(HWC2_FUNCTION_SET_LAYER_BUFFER)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + buffer, acquireFence)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer buffer"; + } + } + + void setLayerColor(hwc2_display_t display, hwc2_layer_t layer, + hwc_color_t color, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_COLOR>( + getFunction(HWC2_FUNCTION_SET_LAYER_COLOR)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + color)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer color"; + } + } + + void setLayerDataspace(hwc2_display_t display, hwc2_layer_t layer, + android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DATASPACE>( + getFunction(HWC2_FUNCTION_SET_LAYER_DATASPACE)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + layer, dataspace)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer dataspace"; + } + } + + void setLayerDisplayFrame(hwc2_display_t display, hwc2_layer_t layer, + const hwc_rect_t& displayFrame, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>( + getFunction(HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + displayFrame)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer display" + " frame"; + } + } + + void setLayerPlaneAlpha(hwc2_display_t display, hwc2_layer_t layer, + float alpha, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_PLANE_ALPHA>( + getFunction(HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + alpha)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer plane alpha " + << alpha; + } + } + + void setLayerSourceCrop(hwc2_display_t display, hwc2_layer_t layer, + const hwc_frect_t& sourceCrop, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_SOURCE_CROP>( + getFunction(HWC2_FUNCTION_SET_LAYER_SOURCE_CROP)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + sourceCrop)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer source crop"; + } + } + + void setLayerSurfaceDamage(hwc2_display_t display, hwc2_layer_t layer, + const hwc_region_t& surfaceDamage, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>( + getFunction(HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + surfaceDamage)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer surface" + " damage"; + } + } + + void setLayerTransform(hwc2_display_t display, hwc2_layer_t layer, + hwc_transform_t transform, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_TRANSFORM>( + getFunction(HWC2_FUNCTION_SET_LAYER_TRANSFORM)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + transform)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer transform " + << getTransformName(transform); + } + } + + void setLayerVisibleRegion(hwc2_display_t display, hwc2_layer_t layer, + const hwc_region_t& visibleRegion, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_VISIBLE_REGION>( + getFunction(HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + visibleRegion)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer visible" + " region"; + } + } + + void setLayerZOrder(hwc2_display_t display, hwc2_layer_t layer, + uint32_t zOrder, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_Z_ORDER>( + getFunction(HWC2_FUNCTION_SET_LAYER_Z_ORDER)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, + zOrder)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer z order " + << zOrder; + } + } + + void validateDisplay(hwc2_display_t display, uint32_t* outNumTypes, + uint32_t* outNumRequests, hwc2_error_t* outErr) + { + auto pfn = reinterpret_cast<HWC2_PFN_VALIDATE_DISPLAY>( + getFunction(HWC2_FUNCTION_VALIDATE_DISPLAY)); + ASSERT_TRUE(pfn) << "failed to get function"; + + *outErr = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + outNumTypes, outNumRequests)); + } + + void validateDisplay(hwc2_display_t display, uint32_t* outNumTypes, + uint32_t* outNumRequests, bool* outHasChanges) + { + hwc2_error_t err = HWC2_ERROR_NONE; + + EXPECT_NO_FATAL_FAILURE(validateDisplay(display, outNumTypes, + outNumRequests, &err)); + + if (err != HWC2_ERROR_HAS_CHANGES) { + *outHasChanges = false; + EXPECT_EQ(err, HWC2_ERROR_NONE) << "failed to validate display"; + } else { + *outHasChanges = true; + } + } + + void getDisplayRequests(hwc2_display_t display, + hwc2_display_request_t* outDisplayRequests, + std::vector<hwc2_layer_t>* outLayers, + std::vector<hwc2_layer_request_t>* outLayerRequests, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_REQUESTS>( + getFunction(HWC2_FUNCTION_GET_DISPLAY_REQUESTS)); + ASSERT_TRUE(pfn) << "failed to get function"; + + uint32_t numElements = 0; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + reinterpret_cast<int32_t*>(outDisplayRequests), &numElements, + nullptr, nullptr)); + + if (err == HWC2_ERROR_NONE && numElements > 0) { + outLayers->resize(numElements); + outLayerRequests->resize(numElements); + + err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + reinterpret_cast<int32_t*>(outDisplayRequests), &numElements, + reinterpret_cast<uint64_t*>(outLayers->data()), + reinterpret_cast<int32_t*>(outLayerRequests->data()))); + } + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display requests"; + } + } + + void handleRequests(hwc2_display_t display, + const std::vector<hwc2_layer_t>& layers, uint32_t numRequests, + std::set<hwc2_layer_t>* outClearLayers = nullptr, + bool* outFlipClientTarget = nullptr) + { + hwc2_display_request_t displayRequest = + static_cast<hwc2_display_request_t>(0); + std::vector<hwc2_layer_t> requestedLayers; + std::vector<hwc2_layer_request_t> requests; + + ASSERT_NO_FATAL_FAILURE(getDisplayRequests(display, &displayRequest, + &requestedLayers, &requests)); + + EXPECT_EQ(numRequests, requests.size()) << "validate returned " + << numRequests << " requests and get display requests returned " + << requests.size() << " requests"; + + for (size_t i = 0; i < requests.size(); i++) { + hwc2_layer_t requestedLayer = requestedLayers.at(i); + hwc2_layer_request_t request = requests.at(i); + + EXPECT_EQ(std::count(layers.begin(), layers.end(), requestedLayer), + 0) << "get display requests returned an unknown layer"; + EXPECT_NE(request, 0) << "returned empty request for layer " + << requestedLayer; + + if (outClearLayers && request + == HWC2_LAYER_REQUEST_CLEAR_CLIENT_TARGET) + outClearLayers->insert(requestedLayer); + } + + if (outFlipClientTarget) + *outFlipClientTarget = displayRequest + & HWC2_DISPLAY_REQUEST_FLIP_CLIENT_TARGET; + } + + void getChangedCompositionTypes(hwc2_display_t display, + std::vector<hwc2_layer_t>* outLayers, + std::vector<hwc2_composition_t>* outTypes, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>( + getFunction(HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES)); + ASSERT_TRUE(pfn) << "failed to get function"; + + uint32_t numElements = 0; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + &numElements, nullptr, nullptr)); + + if (err == HWC2_ERROR_NONE && numElements > 0) { + outLayers->resize(numElements); + outTypes->resize(numElements); + + err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + &numElements, reinterpret_cast<uint64_t*>(outLayers->data()), + reinterpret_cast<int32_t*>(outTypes->data()))); + } + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get changed" + " composition types"; + } + } + + void handleCompositionChanges(hwc2_display_t display, + const Hwc2TestLayers& testLayers, + const std::vector<hwc2_layer_t>& layers, uint32_t numTypes, + std::set<hwc2_layer_t>* outClientLayers = nullptr) + { + std::vector<hwc2_layer_t> changedLayers; + std::vector<hwc2_composition_t> types; + + ASSERT_NO_FATAL_FAILURE(getChangedCompositionTypes(display, + &changedLayers, &types)); + + EXPECT_EQ(numTypes, types.size()) << "validate returned " + << numTypes << " types and get changed composition types" + " returned " << types.size() << " types"; + + for (size_t i = 0; i < types.size(); i++) { + + auto layer = std::find(layers.begin(), layers.end(), + changedLayers.at(i)); + + EXPECT_TRUE(layer != layers.end() || !testLayers.contains(*layer)) + << "get changed composition types returned an unknown layer"; + + hwc2_composition_t requestedType = testLayers.getComposition(*layer); + hwc2_composition_t returnedType = types.at(i); + + EXPECT_NE(returnedType, HWC2_COMPOSITION_INVALID) << "get changed" + " composition types returned invalid composition"; + + switch (requestedType) { + case HWC2_COMPOSITION_CLIENT: + EXPECT_TRUE(false) << getCompositionName(returnedType) + << " cannot be changed"; + break; + case HWC2_COMPOSITION_DEVICE: + case HWC2_COMPOSITION_SOLID_COLOR: + EXPECT_EQ(returnedType, HWC2_COMPOSITION_CLIENT) + << "composition of type " + << getCompositionName(requestedType) + << " can only be changed to " + << getCompositionName(HWC2_COMPOSITION_CLIENT); + break; + case HWC2_COMPOSITION_CURSOR: + case HWC2_COMPOSITION_SIDEBAND: + EXPECT_TRUE(returnedType == HWC2_COMPOSITION_CLIENT + || returnedType == HWC2_COMPOSITION_DEVICE) + << "composition of type " + << getCompositionName(requestedType) + << " can only be changed to " + << getCompositionName(HWC2_COMPOSITION_CLIENT) << " or " + << getCompositionName(HWC2_COMPOSITION_DEVICE); + break; + default: + EXPECT_TRUE(false) << "unknown type " + << getCompositionName(requestedType); + break; + } + + if (outClientLayers) + if (returnedType == HWC2_COMPOSITION_CLIENT) + outClientLayers->insert(*layer); + } + + if (outClientLayers) { + for (auto layer : layers) { + if (testLayers.getComposition(layer) == HWC2_COMPOSITION_CLIENT) + outClientLayers->insert(layer); + } + } + } + + void acceptDisplayChanges(hwc2_display_t display, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>( + getFunction(HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to accept display changes"; + } + } + + void getClientTargetSupport(hwc2_display_t display, int32_t width, + int32_t height, android_pixel_format_t format, + android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>( + getFunction(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, width, + height, format, dataspace)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get client target" + " support"; + } + } + + void setClientTarget(hwc2_display_t display, buffer_handle_t handle, + int32_t acquireFence, android_dataspace_t dataspace, + hwc_region_t damage, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_CLIENT_TARGET>( + getFunction(HWC2_FUNCTION_SET_CLIENT_TARGET)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, handle, + acquireFence, dataspace, damage)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set client target"; + } + } + + void presentDisplay(hwc2_display_t display, int32_t* outPresentFence, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_PRESENT_DISPLAY>( + getFunction(HWC2_FUNCTION_PRESENT_DISPLAY)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + outPresentFence)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to present display"; + } + } + + void getReleaseFences(hwc2_display_t display, + std::vector<hwc2_layer_t>* outLayers, + std::vector<int32_t>* outFences, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_RELEASE_FENCES>( + getFunction(HWC2_FUNCTION_GET_RELEASE_FENCES)); + ASSERT_TRUE(pfn) << "failed to get function"; + + uint32_t numElements = 0; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + &numElements, nullptr, nullptr)); + + if (err == HWC2_ERROR_NONE) { + outLayers->resize(numElements); + outFences->resize(numElements); + + err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + &numElements, outLayers->data(), outFences->data())); + } + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get release fences"; + } + } + + void getColorModes(hwc2_display_t display, + std::vector<android_color_mode_t>* outColorModes, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_COLOR_MODES>( + getFunction(HWC2_FUNCTION_GET_COLOR_MODES)); + ASSERT_TRUE(pfn) << "failed to get function"; + + uint32_t numColorModes = 0; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + &numColorModes, nullptr)); + if (err == HWC2_ERROR_NONE) { + outColorModes->resize(numColorModes); + + err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + &numColorModes, + reinterpret_cast<int32_t*>(outColorModes->data()))); + } + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get color modes for" + " display " << display; + } + } + + void setColorMode(hwc2_display_t display, android_color_mode_t colorMode, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_MODE>( + getFunction(HWC2_FUNCTION_SET_COLOR_MODE)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + static_cast<int32_t>(colorMode))); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color mode " + << colorMode; + } + } + + void getHdrCapabilities(hwc2_display_t display, + std::vector<android_hdr_t>* outTypes, float* outMaxLuminance, + float* outMaxAverageLuminance, float* outMinLuminance, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_HDR_CAPABILITIES>( + getFunction(HWC2_FUNCTION_GET_HDR_CAPABILITIES)); + ASSERT_TRUE(pfn) << "failed to get function"; + + uint32_t numTypes = 0; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + &numTypes, nullptr, outMaxLuminance, outMaxAverageLuminance, + outMinLuminance)); + + if (err == HWC2_ERROR_NONE) { + outTypes->resize(numTypes); + + err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &numTypes, + reinterpret_cast<int32_t*>(outTypes->data()), outMaxLuminance, + outMaxAverageLuminance, outMinLuminance)); + } + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get hdr capabilities" + " for display " << display; + } + } + + void setColorTransform(hwc2_display_t display, + const std::array<float, 16>& matrix, android_color_transform_t hint, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_TRANSFORM>( + getFunction(HWC2_FUNCTION_SET_COLOR_TRANSFORM)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, + matrix.data(), hint)); + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color transform " + << hint; + } + } + + void createVirtualDisplay(uint32_t width, uint32_t height, + android_pixel_format_t* outFormat, hwc2_display_t* outDisplay, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>( + getFunction(HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, width, height, + reinterpret_cast<int32_t*>(outFormat), outDisplay)); + + if (err == HWC2_ERROR_NONE) + mVirtualDisplays.insert(*outDisplay); + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create virtual display"; + } + } + + void destroyVirtualDisplay(hwc2_display_t display, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>( + getFunction(HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display)); + + if (err == HWC2_ERROR_NONE) + mVirtualDisplays.erase(display); + + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to destroy virtual display"; + } + } + + void getMaxVirtualDisplayCount(uint32_t* outMaxCnt) + { + auto pfn = reinterpret_cast<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>( + getFunction(HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT)); + ASSERT_TRUE(pfn) << "failed to get function"; + + *outMaxCnt = pfn(mHwc2Device); + } + + void setOutputBuffer(hwc2_display_t display, buffer_handle_t buffer, + int32_t releaseFence, hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast<HWC2_PFN_SET_OUTPUT_BUFFER>( + getFunction(HWC2_FUNCTION_SET_OUTPUT_BUFFER)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, buffer, + releaseFence)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set output buffer"; + } + } + + void dump(std::string* outBuffer) + { + auto pfn = reinterpret_cast<HWC2_PFN_DUMP>( + getFunction(HWC2_FUNCTION_DUMP)); + ASSERT_TRUE(pfn) << "failed to get function"; + + uint32_t size = 0; + + pfn(mHwc2Device, &size, nullptr); + + std::vector<char> buffer(size); + + pfn(mHwc2Device, &size, buffer.data()); + + outBuffer->assign(buffer.data()); + } + + void getBadDisplay(hwc2_display_t* outDisplay) + { + for (hwc2_display_t display = 0; display < UINT64_MAX; display++) { + if (mDisplays.count(display) == 0) { + *outDisplay = display; + return; + } + } + ASSERT_TRUE(false) << "Unable to find bad display. UINT64_MAX displays" + " are registered. This should never happen."; + } + + void waitForVsync(hwc2_display_t* outDisplay = nullptr, + int64_t* outTimestamp = nullptr) + { + std::unique_lock<std::mutex> lock(mVsyncMutex); + ASSERT_EQ(mVsyncCv.wait_for(lock, std::chrono::seconds(3)), + std::cv_status::no_timeout) << "timed out attempting to get" + " vsync callback"; + if (outDisplay) + *outDisplay = mVsyncDisplay; + if (outTimestamp) + *outTimestamp = mVsyncTimestamp; + } + + void enableVsync(hwc2_display_t display) + { + ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, this, + reinterpret_cast<hwc2_function_pointer_t>( + hwc2TestVsyncCallback))); + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE)); + } + + void disableVsync(hwc2_display_t display) + { + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE)); + } + +protected: + hwc2_function_pointer_t getFunction(hwc2_function_descriptor_t descriptor) + { + return mHwc2Device->getFunction(mHwc2Device, descriptor); + } + + void getCapabilities(std::vector<hwc2_capability_t>* outCapabilities) + { + uint32_t num = 0; + + mHwc2Device->getCapabilities(mHwc2Device, &num, nullptr); + + outCapabilities->resize(num); + + mHwc2Device->getCapabilities(mHwc2Device, &num, + reinterpret_cast<int32_t*>(outCapabilities->data())); + } + + /* Registers a hotplug callback and waits for hotplug callbacks. This + * function will have no effect if called more than once. */ + void populateDisplays() + { + /* Sets the hotplug status to receiving */ + { + std::lock_guard<std::mutex> lock(mHotplugMutex); + + if (mHotplugStatus != Hwc2TestHotplugStatus::Init) + return; + mHotplugStatus = Hwc2TestHotplugStatus::Receiving; + } + + /* Registers the callback. This function call cannot be locked because + * a callback could happen on the same thread */ + ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_HOTPLUG, this, + reinterpret_cast<hwc2_function_pointer_t>( + hwc2TestHotplugCallback))); + + /* Waits for hotplug events. If a hotplug event has not come within 1 + * second, stop waiting. */ + std::unique_lock<std::mutex> lock(mHotplugMutex); + + while (mHotplugCv.wait_for(lock, std::chrono::seconds(1)) != + std::cv_status::timeout) { } + + /* Sets the hotplug status to done. Future calls will have no effect */ + mHotplugStatus = Hwc2TestHotplugStatus::Done; + } + + /* NOTE: will create min(newlayerCnt, max supported layers) layers */ + void createLayers(hwc2_display_t display, + std::vector<hwc2_layer_t>* outLayers, size_t newLayerCnt) + { + std::vector<hwc2_layer_t> newLayers; + hwc2_layer_t layer; + hwc2_error_t err = HWC2_ERROR_NONE; + + for (size_t i = 0; i < newLayerCnt; i++) { + + EXPECT_NO_FATAL_FAILURE(createLayer(display, &layer, &err)); + if (err == HWC2_ERROR_NO_RESOURCES) + break; + if (err != HWC2_ERROR_NONE) { + newLayers.clear(); + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create layer"; + } + newLayers.push_back(layer); + } + + *outLayers = std::move(newLayers); + } + + void destroyLayers(hwc2_display_t display, + std::vector<hwc2_layer_t>&& layers) + { + for (hwc2_layer_t layer : layers) { + EXPECT_NO_FATAL_FAILURE(destroyLayer(display, layer)); + } + } + + void getInvalidConfig(hwc2_display_t display, hwc2_config_t* outConfig) + { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + hwc2_config_t CONFIG_MAX = UINT32_MAX; + + ASSERT_LE(configs.size() - 1, CONFIG_MAX) << "every config value" + " (2^32 values) has been taken which shouldn't happen"; + + hwc2_config_t config; + for (config = 0; config < CONFIG_MAX; config++) { + if (std::count(configs.begin(), configs.end(), config) == 0) + break; + } + + *outConfig = config; + } + + /* Calls a set property function from Hwc2Test to set a property value from + * Hwc2TestLayer to hwc2_layer_t on hwc2_display_t */ + using TestLayerPropertyFunction = void (*)(Hwc2Test* test, + hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr); + + /* Calls a set property function from Hwc2Test to set property values from + * Hwc2TestLayers to hwc2_layer_t on hwc2_display_t */ + using TestLayerPropertiesFunction = void (*)(Hwc2Test* test, + hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayers* testLayers); + + /* Calls a set property function from Hwc2Test to set a bad property value + * on hwc2_layer_t on hwc2_display_t */ + using TestLayerPropertyBadLayerFunction = void (*)(Hwc2Test* test, + hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr); + + /* Calls a set property function from Hwc2Test to set a bad property value + * on hwc2_layer_t on hwc2_display_t */ + using TestLayerPropertyBadParameterFunction = void (*)(Hwc2Test* test, + hwc2_display_t display, hwc2_layer_t layer, hwc2_error_t* outErr); + + /* Is called after a display is powered on and all layer properties have + * been set. It should be used to test functions such as validate, accepting + * changes, present, etc. */ + using TestDisplayLayersFunction = void (*)(Hwc2Test* test, + hwc2_display_t display, const std::vector<hwc2_layer_t>& layers, + Hwc2TestLayers* testLayers); + + /* It is called on an non validated display */ + using TestDisplayNonValidatedLayersFunction = void (*)(Hwc2Test* test, + hwc2_display_t display, std::vector<hwc2_layer_t>* layers); + + /* Tests client target support on a particular display and config */ + using TestClientTargetSupportFunction = void (*)(Hwc2Test* test, + hwc2_display_t display, + const Hwc2TestClientTargetSupport& testClientTargetSupport); + + /* Tests a particular active display config */ + using TestActiveDisplayConfigFunction = void (*)(Hwc2Test* test, + hwc2_display_t display); + + /* Tests a newly created virtual display */ + using TestCreateVirtualDisplayFunction = void (*)(Hwc2Test* test, + hwc2_display_t display, Hwc2TestVirtualDisplay* testVirtualDisplay); + + /* Advances a property of Hwc2TestLayer */ + using AdvanceProperty = bool (*)(Hwc2TestLayer* testLayer); + + /* Advances properties of Hwc2TestLayers */ + using AdvanceProperties = bool (*)(Hwc2TestLayers* testLayer); + + /* Advances properties of Hwc2TestClientTargetSupport */ + using AdvanceClientTargetSupport = bool (*)( + Hwc2TestClientTargetSupport* testClientTargetSupport); + + /* For each active display it cycles through each display config and tests + * each property value. It creates a layer, sets the property and then + * destroys the layer */ + void setLayerProperty(Hwc2TestCoverage coverage, + TestLayerPropertyFunction function, AdvanceProperty advance) + { + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + hwc2_layer_t layer; + Area displayArea; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, + &displayArea)); + Hwc2TestLayer testLayer(coverage, displayArea); + + do { + ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); + + ASSERT_NO_FATAL_FAILURE(function(this, display, layer, + &testLayer, nullptr)); + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); + } while (advance(&testLayer)); + } + } + } + + /* For each active display it cycles through each display config and tests + * each property value. It creates a layer, cycles through each property + * value and updates the layer property value and then destroys the layer */ + void setLayerPropertyUpdate(Hwc2TestCoverage coverage, + TestLayerPropertyFunction function, AdvanceProperty advance) + { + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + hwc2_layer_t layer; + Area displayArea; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, + &displayArea)); + Hwc2TestLayer testLayer(coverage, displayArea); + + ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); + + do { + ASSERT_NO_FATAL_FAILURE(function(this, display, layer, + &testLayer, nullptr)); + } while (advance(&testLayer)); + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); + } + } + } + + /* For each active display it cycles through each display config and tests + * each property value. It creates multiple layers, calls the + * TestLayerPropertiesFunction to set property values and then + * destroys the layers */ + void setLayerProperties(Hwc2TestCoverage coverage, size_t layerCnt, + TestLayerPropertiesFunction function, AdvanceProperties advance) + { + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + std::vector<hwc2_layer_t> layers; + Area displayArea; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, + &displayArea)); + + ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt)); + Hwc2TestLayers testLayers(layers, coverage, displayArea); + + do { + for (auto layer : layers) { + EXPECT_NO_FATAL_FAILURE(function(this, display, layer, + &testLayers)); + } + } while (advance(&testLayers)); + + ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers))); + } + } + } + + /* For each active display it cycles through each display config. + * 1) It attempts to set a valid property value to bad layer handle. + * 2) It creates a layer x and attempts to set a valid property value to + * layer x + 1 + * 3) It destroys the layer x and attempts to set a valid property value to + * the destroyed layer x. + */ + void setLayerPropertyBadLayer(Hwc2TestCoverage coverage, + TestLayerPropertyBadLayerFunction function) + { + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + hwc2_layer_t layer = 0; + Area displayArea; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, + &displayArea)); + Hwc2TestLayer testLayer(coverage, displayArea); + + ASSERT_NO_FATAL_FAILURE(function(this, display, layer, + &testLayer, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); + + ASSERT_NO_FATAL_FAILURE(function(this, display, layer + 1, + &testLayer, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); + + ASSERT_NO_FATAL_FAILURE(function(this, display, layer, + &testLayer, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + } + } + } + + /* For each active display it cycles through each display config and tests + * each property value. It creates a layer, sets a bad property value and + * then destroys the layer */ + void setLayerPropertyBadParameter(TestLayerPropertyBadParameterFunction function) + { + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + hwc2_layer_t layer; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + + ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); + + ASSERT_NO_FATAL_FAILURE(function(this, display, layer, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong" + " error code"; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); + } + } + } + + /* For each active display it powers on the display, cycles through each + * config and creates a set of layers with a certain amount of coverage. + * For each active display, for each config and for each set of layers, + * it calls the TestDisplayLayersFunction */ + void displayLayers(Hwc2TestCoverage coverage, size_t layerCnt, + TestDisplayLayersFunction function) + { + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + Area displayArea; + std::vector<hwc2_layer_t> layers; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea)); + + ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt)); + Hwc2TestLayers testLayers(layers, coverage, displayArea); + + do { + bool skip; + + ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers, + &testLayers, &skip)); + if (!skip) + EXPECT_NO_FATAL_FAILURE(function(this, display, layers, + &testLayers)); + + } while (testLayers.advance()); + + ASSERT_NO_FATAL_FAILURE(destroyLayers(display, + std::move(layers))); + } + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } + } + + /* For each active display, it calls the + * TestDisplayNonValidatedLayersFunction on a variety on non-validated + * layer combinations */ + void displayNonValidatedLayers(size_t layerCnt, + TestDisplayNonValidatedLayersFunction function) + { + for (auto display : mDisplays) { + uint32_t numTypes, numRequests; + std::vector<hwc2_layer_t> layers; + bool hasChanges; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + + EXPECT_NO_FATAL_FAILURE(function(this, display, &layers)); + + ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt)); + + EXPECT_NO_FATAL_FAILURE(function(this, display, &layers)); + + for (auto layer : layers) { + ASSERT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer, + HWC2_COMPOSITION_CLIENT)); + } + + EXPECT_NO_FATAL_FAILURE(function(this, display, &layers)); + + ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, + &numRequests, &hasChanges)); + + for (auto layer : layers) { + ASSERT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer, + HWC2_COMPOSITION_DEVICE)); + } + + EXPECT_NO_FATAL_FAILURE(function(this, display, &layers)); + + ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers))); + + EXPECT_NO_FATAL_FAILURE(function(this, display, &layers)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } + } + + /* Test client target support on each config on each active display */ + void setClientTargetSupport(Hwc2TestCoverage coverage, + TestClientTargetSupportFunction function, + AdvanceClientTargetSupport advance) + { + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + Area displayArea; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, + &displayArea)); + Hwc2TestClientTargetSupport testClientTargetSupport(coverage, + displayArea); + + do { + EXPECT_NO_FATAL_FAILURE(function(this, display, + testClientTargetSupport)); + + } while (advance(&testClientTargetSupport)); + } + } + } + + /* Cycles through each config on each active display and calls + * a TestActiveDisplayConfigFunction */ + void setActiveDisplayConfig(TestActiveDisplayConfigFunction function) + { + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + + EXPECT_NO_FATAL_FAILURE(function(this, display)); + } + } + } + + /* Creates a virtual display for testing */ + void createVirtualDisplay(Hwc2TestCoverage coverage, + TestCreateVirtualDisplayFunction function) + { + Hwc2TestVirtualDisplay testVirtualDisplay(coverage); + + do { + hwc2_display_t display; + hwc2_error_t err = HWC2_ERROR_NONE; + + const UnsignedArea& dimension = + testVirtualDisplay.getDisplayDimension(); + android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888; + + ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width, + dimension.height, &desiredFormat, &display, &err)); + + EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_NO_RESOURCES + || err == HWC2_ERROR_UNSUPPORTED) + << "returned wrong error code"; + EXPECT_GE(desiredFormat, 0) << "invalid format"; + + if (err != HWC2_ERROR_NONE) + continue; + + EXPECT_NO_FATAL_FAILURE(function(this, display, + &testVirtualDisplay)); + + ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display)); + + } while (testVirtualDisplay.advance()); + } + + + void getActiveConfigAttribute(hwc2_display_t display, + hwc2_attribute_t attribute, int32_t* outValue) + { + hwc2_config_t config; + ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &config)); + ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, + attribute, outValue)); + ASSERT_GE(*outValue, 0) << "failed to get valid " + << getAttributeName(attribute); + } + + void getActiveDisplayArea(hwc2_display_t display, Area* displayArea) + { + ASSERT_NO_FATAL_FAILURE(getActiveConfigAttribute(display, + HWC2_ATTRIBUTE_WIDTH, &displayArea->width)); + ASSERT_NO_FATAL_FAILURE(getActiveConfigAttribute(display, + HWC2_ATTRIBUTE_HEIGHT, &displayArea->height)); + } + + void closeFences(hwc2_display_t display, int32_t presentFence) + { + std::vector<hwc2_layer_t> layers; + std::vector<int32_t> fences; + const int msWait = 3000; + + if (presentFence >= 0) { + ASSERT_GE(sync_wait(presentFence, msWait), 0); + close(presentFence); + } + + ASSERT_NO_FATAL_FAILURE(getReleaseFences(display, &layers, &fences)); + EXPECT_EQ(layers.size(), fences.size()); + + for (int32_t fence : fences) { + EXPECT_GE(sync_wait(fence, msWait), 0); + if (fence >= 0) + close(fence); + } + } + + void setLayerProperties(hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayers* testLayers, bool* outSkip) + { + hwc2_composition_t composition; + buffer_handle_t handle = nullptr; + int32_t acquireFence; + hwc2_error_t err = HWC2_ERROR_NONE; + *outSkip = true; + + if (!testLayers->contains(layer)) + return; + + composition = testLayers->getComposition(layer); + + /* If the device cannot support a buffer format, then do not continue */ + if ((composition == HWC2_COMPOSITION_DEVICE + || composition == HWC2_COMPOSITION_CURSOR) + && testLayers->getBuffer(layer, &handle, &acquireFence) < 0) + return; + + EXPECT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer, + composition, &err)); + if (err == HWC2_ERROR_UNSUPPORTED) + EXPECT_TRUE(composition != HWC2_COMPOSITION_CLIENT + && composition != HWC2_COMPOSITION_DEVICE); + + const hwc_rect_t cursor = testLayers->getCursorPosition(layer); + + EXPECT_NO_FATAL_FAILURE(setLayerBuffer(display, layer, handle, + acquireFence)); + EXPECT_NO_FATAL_FAILURE(setLayerBlendMode(display, layer, + testLayers->getBlendMode(layer))); + EXPECT_NO_FATAL_FAILURE(setLayerColor(display, layer, + testLayers->getColor(layer))); + EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer, cursor.left, + cursor.top)); + EXPECT_NO_FATAL_FAILURE(setLayerDataspace(display, layer, + testLayers->getDataspace(layer))); + EXPECT_NO_FATAL_FAILURE(setLayerDisplayFrame(display, layer, + testLayers->getDisplayFrame(layer))); + EXPECT_NO_FATAL_FAILURE(setLayerPlaneAlpha(display, layer, + testLayers->getPlaneAlpha(layer))); + EXPECT_NO_FATAL_FAILURE(setLayerSourceCrop(display, layer, + testLayers->getSourceCrop(layer))); + EXPECT_NO_FATAL_FAILURE(setLayerSurfaceDamage(display, layer, + testLayers->getSurfaceDamage(layer))); + EXPECT_NO_FATAL_FAILURE(setLayerTransform(display, layer, + testLayers->getTransform(layer))); + EXPECT_NO_FATAL_FAILURE(setLayerVisibleRegion(display, layer, + testLayers->getVisibleRegion(layer))); + EXPECT_NO_FATAL_FAILURE(setLayerZOrder(display, layer, + testLayers->getZOrder(layer))); + + *outSkip = false; + } + + void setLayerProperties(hwc2_display_t display, + const std::vector<hwc2_layer_t>& layers, + Hwc2TestLayers* testLayers, bool* outSkip) + { + for (auto layer : layers) { + EXPECT_NO_FATAL_FAILURE(setLayerProperties(display, layer, + testLayers, outSkip)); + if (*outSkip) + return; + } + } + + void setClientTarget(hwc2_display_t display, + Hwc2TestClientTarget* testClientTarget, + const Hwc2TestLayers& testLayers, + const std::set<hwc2_layer_t>& clientLayers, + const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget, + const Area& displayArea) + { + android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; + hwc_region_t damage = { }; + buffer_handle_t handle; + int32_t acquireFence; + + ASSERT_EQ(testClientTarget->getBuffer(testLayers, clientLayers, + clearLayers, flipClientTarget, displayArea, &handle, + &acquireFence), 0); + EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle, acquireFence, + dataspace, damage)); + } + + void presentDisplays(size_t layerCnt, Hwc2TestCoverage coverage, + const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>& + coverageExceptions, bool optimize) + { + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + ASSERT_NO_FATAL_FAILURE(enableVsync(display)); + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + Area displayArea; + std::vector<hwc2_layer_t> layers; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, + &displayArea)); + + ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt)); + Hwc2TestLayers testLayers(layers, coverage, displayArea, + coverageExceptions); + + if (optimize && !testLayers.optimizeLayouts()) + continue; + + std::set<hwc2_layer_t> clientLayers; + std::set<hwc2_layer_t> clearLayers; + Hwc2TestClientTarget testClientTarget; + + do { + uint32_t numTypes, numRequests; + bool hasChanges, skip; + bool flipClientTarget; + int32_t presentFence; + + ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers, + &testLayers, &skip)); + if (skip) + continue; + + ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, + &numRequests, &hasChanges)); + if (hasChanges) + EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size())) + << "wrong number of requests"; + + ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display, + testLayers, layers, numTypes, &clientLayers)); + ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers, + numRequests, &clearLayers, &flipClientTarget)); + ASSERT_NO_FATAL_FAILURE(setClientTarget(display, + &testClientTarget, testLayers, clientLayers, + clearLayers, flipClientTarget, displayArea)); + ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display)); + + ASSERT_NO_FATAL_FAILURE(waitForVsync()); + + EXPECT_NO_FATAL_FAILURE(presentDisplay(display, + &presentFence)); + + ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence)); + + } while (testLayers.advance()); + + ASSERT_NO_FATAL_FAILURE(destroyLayers(display, + std::move(layers))); + } + + ASSERT_NO_FATAL_FAILURE(disableVsync(display)); + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } + } + + hwc2_device_t* mHwc2Device = nullptr; + + enum class Hwc2TestHotplugStatus { + Init = 1, + Receiving, + Done, + }; + + std::mutex mHotplugMutex; + std::condition_variable mHotplugCv; + Hwc2TestHotplugStatus mHotplugStatus = Hwc2TestHotplugStatus::Init; + std::unordered_set<hwc2_display_t> mDisplays; + + /* Store all created layers that have not been destroyed. If an ASSERT_* + * fails, then destroy the layers on exit */ + std::set<std::pair<hwc2_display_t, hwc2_layer_t>> mLayers; + + /* Store the power mode state. If it is not HWC2_POWER_MODE_OFF when + * tearing down the test cases, change it to HWC2_POWER_MODE_OFF */ + std::set<hwc2_display_t> mActiveDisplays; + + /* Store all created virtual displays that have not been destroyed. If an + * ASSERT_* fails, then destroy the virtual displays on exit */ + std::set<hwc2_display_t> mVirtualDisplays; + + std::mutex mVsyncMutex; + std::condition_variable mVsyncCv; + hwc2_display_t mVsyncDisplay; + int64_t mVsyncTimestamp = -1; +}; + +void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData, + hwc2_display_t display, int32_t connection) +{ + if (callbackData) + static_cast<Hwc2Test*>(callbackData)->hotplugCallback(display, + connection); +} + +void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData, + hwc2_display_t display, int64_t timestamp) +{ + if (callbackData) + static_cast<Hwc2Test*>(callbackData)->vsyncCallback(display, + timestamp); +} + +void setBlendMode(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + EXPECT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer, + testLayer->getBlendMode(), outErr)); +} + +void setBuffer(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + buffer_handle_t handle; + android::base::unique_fd acquireFence; + hwc2_composition_t composition = testLayer->getComposition(); + + if (composition == HWC2_COMPOSITION_CLIENT + || composition == HWC2_COMPOSITION_SOLID_COLOR + || composition == HWC2_COMPOSITION_SIDEBAND) + return; + + if (testLayer->getBuffer(&handle, &acquireFence) < 0) + return; + + ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer, + composition)); + EXPECT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer, + handle, acquireFence, outErr)); +} + +void setColor(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, + layer, HWC2_COMPOSITION_SOLID_COLOR)); + ASSERT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display, + layer, testLayer->getPlaneAlpha())); + ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, + layer, testLayer->getBlendMode())); + EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer, + testLayer->getColor(), outErr)); +} + +void setComposition(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + hwc2_composition_t composition = testLayer->getComposition(); + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer, + composition, &err)); + if (outErr) { + *outErr = err; + return; + } + + if (composition != HWC2_COMPOSITION_SIDEBAND) { + EXPECT_EQ(err, HWC2_ERROR_NONE) << "returned wrong error code"; + } else { + EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_UNSUPPORTED) + << "returned wrong error code"; + } +} + +void setCursorPosition(Hwc2Test* test, hwc2_display_t display, + hwc2_layer_t layer, Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, + layer, HWC2_COMPOSITION_CURSOR)); + + const hwc_rect_t cursorPosition = testLayer->getCursorPosition(); + EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer, + cursorPosition.left, cursorPosition.top, outErr)); +} + +void setDataspace(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + EXPECT_NO_FATAL_FAILURE(test->setLayerDataspace(display, layer, + testLayer->getDataspace(), outErr)); +} + +void setDisplayFrame(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + EXPECT_NO_FATAL_FAILURE(test->setLayerDisplayFrame(display, layer, + testLayer->getDisplayFrame(), outErr)); +} + +void setPlaneAlpha(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t *outErr) +{ + ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer, + testLayer->getBlendMode())); + EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display, layer, + testLayer->getPlaneAlpha(), outErr)); +} + +void setSourceCrop(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + EXPECT_NO_FATAL_FAILURE(test->setLayerSourceCrop(display, layer, + testLayer->getSourceCrop(), outErr)); +} + +void setSurfaceDamage(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + EXPECT_NO_FATAL_FAILURE(test->setLayerSurfaceDamage(display, layer, + testLayer->getSurfaceDamage(), outErr)); +} + +void setTransform(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + EXPECT_NO_FATAL_FAILURE(test->setLayerTransform(display, layer, + testLayer->getTransform(), outErr)); +} + +void setVisibleRegion(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + EXPECT_NO_FATAL_FAILURE(test->setLayerVisibleRegion(display, layer, + testLayer->getVisibleRegion(), outErr)); +} + +void setZOrder(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer, + testLayer->getZOrder(), outErr)); +} + +bool advanceBlendMode(Hwc2TestLayer* testLayer) +{ + return testLayer->advanceBlendMode(); +} + +bool advanceBuffer(Hwc2TestLayer* testLayer) +{ + if (testLayer->advanceComposition()) + return true; + return testLayer->advanceBufferArea(); +} + +bool advanceColor(Hwc2TestLayer* testLayer) +{ + /* Color depends on blend mode so advance blend mode last so color is not + * force to update as often */ + if (testLayer->advancePlaneAlpha()) + return true; + if (testLayer->advanceColor()) + return true; + return testLayer->advanceBlendMode(); +} + +bool advanceComposition(Hwc2TestLayer* testLayer) +{ + return testLayer->advanceComposition(); +} + +bool advanceCursorPosition(Hwc2TestLayer* testLayer) +{ + return testLayer->advanceCursorPosition(); +} + +bool advanceDataspace(Hwc2TestLayer* testLayer) +{ + return testLayer->advanceDataspace(); +} + +bool advanceDisplayFrame(Hwc2TestLayer* testLayer) +{ + return testLayer->advanceDisplayFrame(); +} + +bool advancePlaneAlpha(Hwc2TestLayer* testLayer) +{ + return testLayer->advancePlaneAlpha(); +} + +bool advanceSourceCrop(Hwc2TestLayer* testLayer) +{ + if (testLayer->advanceSourceCrop()) + return true; + return testLayer->advanceBufferArea(); +} + +bool advanceSurfaceDamage(Hwc2TestLayer* testLayer) +{ + if (testLayer->advanceSurfaceDamage()) + return true; + return testLayer->advanceBufferArea(); +} + +bool advanceTransform(Hwc2TestLayer* testLayer) +{ + return testLayer->advanceTransform(); +} + +bool advanceVisibleRegions(Hwc2TestLayers* testLayers) +{ + return testLayers->advanceVisibleRegions(); +} + +bool advanceClientTargetSupport( + Hwc2TestClientTargetSupport* testClientTargetSupport) +{ + return testClientTargetSupport->advance(); +} + +static const std::array<hwc2_function_descriptor_t, 42> requiredFunctions = {{ + HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES, + HWC2_FUNCTION_CREATE_LAYER, + HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY, + HWC2_FUNCTION_DESTROY_LAYER, + HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY, + HWC2_FUNCTION_DUMP, + HWC2_FUNCTION_GET_ACTIVE_CONFIG, + HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES, + HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT, + HWC2_FUNCTION_GET_COLOR_MODES, + HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE, + HWC2_FUNCTION_GET_DISPLAY_CONFIGS, + HWC2_FUNCTION_GET_DISPLAY_NAME, + HWC2_FUNCTION_GET_DISPLAY_REQUESTS, + HWC2_FUNCTION_GET_DISPLAY_TYPE, + HWC2_FUNCTION_GET_DOZE_SUPPORT, + HWC2_FUNCTION_GET_HDR_CAPABILITIES, + HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT, + HWC2_FUNCTION_GET_RELEASE_FENCES, + HWC2_FUNCTION_PRESENT_DISPLAY, + HWC2_FUNCTION_REGISTER_CALLBACK, + HWC2_FUNCTION_SET_ACTIVE_CONFIG, + HWC2_FUNCTION_SET_CLIENT_TARGET, + HWC2_FUNCTION_SET_COLOR_MODE, + HWC2_FUNCTION_SET_COLOR_TRANSFORM, + HWC2_FUNCTION_SET_CURSOR_POSITION, + HWC2_FUNCTION_SET_LAYER_BLEND_MODE, + HWC2_FUNCTION_SET_LAYER_BUFFER, + HWC2_FUNCTION_SET_LAYER_COLOR, + HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE, + HWC2_FUNCTION_SET_LAYER_DATASPACE, + HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME, + HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA, + HWC2_FUNCTION_SET_LAYER_SOURCE_CROP, + HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE, + HWC2_FUNCTION_SET_LAYER_TRANSFORM, + HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION, + HWC2_FUNCTION_SET_LAYER_Z_ORDER, + HWC2_FUNCTION_SET_OUTPUT_BUFFER, + HWC2_FUNCTION_SET_POWER_MODE, + HWC2_FUNCTION_SET_VSYNC_ENABLED, + HWC2_FUNCTION_VALIDATE_DISPLAY, +}}; + +/* TESTCASE: Tests that the HWC2 supports all required functions. */ +TEST_F(Hwc2Test, GET_FUNCTION) +{ + for (hwc2_function_descriptor_t descriptor : requiredFunctions) { + hwc2_function_pointer_t pfn = getFunction(descriptor); + EXPECT_TRUE(pfn) << "failed to get function " + << getFunctionDescriptorName(descriptor); + } +} + +/* TESTCASE: Tests that the HWC2 fails to retrieve and invalid function. */ +TEST_F(Hwc2Test, GET_FUNCTION_invalid_function) +{ + hwc2_function_pointer_t pfn = getFunction(HWC2_FUNCTION_INVALID); + EXPECT_FALSE(pfn) << "failed to get invalid function"; +} + +/* TESTCASE: Tests that the HWC2 does not return an invalid capability. */ +TEST_F(Hwc2Test, GET_CAPABILITIES) +{ + std::vector<hwc2_capability_t> capabilities; + + getCapabilities(&capabilities); + + EXPECT_EQ(std::count(capabilities.begin(), capabilities.end(), + HWC2_CAPABILITY_INVALID), 0); +} + +static const std::array<hwc2_callback_descriptor_t, 3> callbackDescriptors = {{ + HWC2_CALLBACK_HOTPLUG, + HWC2_CALLBACK_REFRESH, + HWC2_CALLBACK_VSYNC, +}}; + +/* TESTCASE: Tests that the HWC2 can successfully register all required + * callback functions. */ +TEST_F(Hwc2Test, REGISTER_CALLBACK) +{ + hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>( + const_cast<char*>("data")); + + for (auto descriptor : callbackDescriptors) { + ASSERT_NO_FATAL_FAILURE(registerCallback(descriptor, data, + []() { return; })); + } +} + +/* TESTCASE: Test that the HWC2 fails to register invalid callbacks. */ +TEST_F(Hwc2Test, REGISTER_CALLBACK_bad_parameter) +{ + hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>( + const_cast<char*>("data")); + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_INVALID, data, + []() { return; }, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 can register a callback with null data. */ +TEST_F(Hwc2Test, REGISTER_CALLBACK_null_data) +{ + hwc2_callback_data_t data = nullptr; + + for (auto descriptor : callbackDescriptors) { + ASSERT_NO_FATAL_FAILURE(registerCallback(descriptor, data, + []() { return; })); + } +} + +/* TESTCASE: Tests that the HWC2 returns the correct display type for each + * physical display. */ +TEST_F(Hwc2Test, GET_DISPLAY_TYPE) +{ + for (auto display : mDisplays) { + hwc2_display_type_t type; + + ASSERT_NO_FATAL_FAILURE(getDisplayType(display, &type)); + EXPECT_EQ(type, HWC2_DISPLAY_TYPE_PHYSICAL) << "failed to return" + " correct display type"; + } +} + +/* TESTCASE: Tests that the HWC2 returns an error when the display type of a bad + * display is requested. */ +TEST_F(Hwc2Test, GET_DISPLAY_TYPE_bad_display) +{ + hwc2_display_t display; + hwc2_display_type_t type; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(getDisplayType(display, &type, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 can create and destroy layers. */ +TEST_F(Hwc2Test, CREATE_DESTROY_LAYER) +{ + for (auto display : mDisplays) { + hwc2_layer_t layer; + + ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); + } +} + +/* TESTCASE: Tests that the HWC2 cannot create a layer for a bad display */ +TEST_F(Hwc2Test, CREATE_LAYER_bad_display) +{ + hwc2_display_t display; + hwc2_layer_t layer; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 will either support a large number of resources + * or will return no resources. */ +TEST_F(Hwc2Test, CREATE_LAYER_no_resources) +{ + const size_t layerCnt = 1000; + + for (auto display : mDisplays) { + std::vector<hwc2_layer_t> layers; + + ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt)); + + ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers))); + } +} + +/* TESTCASE: Tests that the HWC2 cannot destroy a layer for a bad display */ +TEST_F(Hwc2Test, DESTROY_LAYER_bad_display) +{ + hwc2_display_t badDisplay; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&badDisplay)); + + for (auto display : mDisplays) { + hwc2_layer_t layer = 0; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(badDisplay, layer, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); + + ASSERT_NO_FATAL_FAILURE(destroyLayer(badDisplay, layer, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); + } +} + +/* TESTCASE: Tests that the HWC2 cannot destory a bad layer */ +TEST_F(Hwc2Test, DESTROY_LAYER_bad_layer) +{ + for (auto display : mDisplays) { + hwc2_layer_t layer; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX / 2, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, 0, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX - 1, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, 1, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer + 1, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; + } +} + +static const std::array<hwc2_attribute_t, 2> requiredAttributes = {{ + HWC2_ATTRIBUTE_WIDTH, + HWC2_ATTRIBUTE_HEIGHT, +}}; + +static const std::array<hwc2_attribute_t, 3> optionalAttributes = {{ + HWC2_ATTRIBUTE_VSYNC_PERIOD, + HWC2_ATTRIBUTE_DPI_X, + HWC2_ATTRIBUTE_DPI_Y, +}}; + +/* TESTCASE: Tests that the HWC2 can return display attributes for a valid + * config. */ +TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE) +{ + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + int32_t value; + + for (auto attribute : requiredAttributes) { + ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, + attribute, &value)); + EXPECT_GE(value, 0) << "missing required attribute " + << getAttributeName(attribute) << " for config " + << config; + } + for (auto attribute : optionalAttributes) { + ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, + attribute, &value)); + } + } + } +} + +/* TESTCASE: Tests that the HWC2 will return a value of -1 for an invalid + * attribute */ +TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_invalid_attribute) +{ + const hwc2_attribute_t attribute = HWC2_ATTRIBUTE_INVALID; + + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + int32_t value; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, + attribute, &value, &err)); + EXPECT_EQ(value, -1) << "failed to return -1 for an invalid" + " attribute for config " << config; + } + } +} + +/* TESTCASE: Tests that the HWC2 will fail to get attributes for a bad display */ +TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_bad_display) +{ + hwc2_display_t display; + const hwc2_config_t config = 0; + int32_t value; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + for (auto attribute : requiredAttributes) { + ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, attribute, + &value, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + } + + for (auto attribute : optionalAttributes) { + ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, attribute, + &value, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + } +} + +/* TESTCASE: Tests that the HWC2 will fail to get attributes for a bad config */ +TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_bad_config) +{ + for (auto display : mDisplays) { + hwc2_config_t config; + int32_t value; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getInvalidConfig(display, &config)); + + for (auto attribute : requiredAttributes) { + ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, + attribute, &value, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code"; + } + + for (auto attribute : optionalAttributes) { + ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, + attribute, &value, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code"; + } + } +} + +/* TESTCASE: Tests that the HWC2 will get display configs for active displays */ +TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS) +{ + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + } +} + +/* TESTCASE: Tests that the HWC2 will not get display configs for bad displays */ +TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_bad_display) +{ + hwc2_display_t display; + std::vector<hwc2_config_t> configs; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs, &err)); + + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + EXPECT_TRUE(configs.empty()) << "returned configs for bad display"; +} + +/* TESTCASE: Tests that the HWC2 will return the same config list multiple + * times in a row. */ +TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_same) +{ + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs1, configs2; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs1)); + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs2)); + + EXPECT_TRUE(std::is_permutation(configs1.begin(), configs1.end(), + configs2.begin())) << "returned two different config sets"; + } +} + +/* TESTCASE: Tests that the HWC2 does not return duplicate display configs */ +TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_duplicate) +{ + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + std::unordered_set<hwc2_config_t> configsSet(configs.begin(), + configs.end()); + EXPECT_EQ(configs.size(), configsSet.size()) << "returned duplicate" + " configs"; + } +} + +/* TESTCASE: Tests that the HWC2 returns the active config for a display */ +TEST_F(Hwc2Test, GET_ACTIVE_CONFIG) +{ + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + hwc2_config_t activeConfig; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig)); + + EXPECT_EQ(activeConfig, config) << "failed to get active config"; + } + } +} + +/* TESTCASE: Tests that the HWC2 does not return an active config for a bad + * display. */ +TEST_F(Hwc2Test, GET_ACTIVE_CONFIG_bad_display) +{ + hwc2_display_t display; + hwc2_config_t activeConfig; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig, &err)); + + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 either begins with a valid active config + * or returns an error when getActiveConfig is called. */ +TEST_F(Hwc2Test, GET_ACTIVE_CONFIG_bad_config) +{ + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + hwc2_config_t activeConfig; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + if (configs.empty()) + return; + + ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig, &err)); + if (err == HWC2_ERROR_NONE) { + EXPECT_NE(std::count(configs.begin(), configs.end(), + activeConfig), 0) << "active config is not found in " + " configs for display"; + } else { + EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code"; + } + } +} + +/* TESTCASE: Tests that the HWC2 can set every display config as an active + * config */ +TEST_F(Hwc2Test, SET_ACTIVE_CONFIG) +{ + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + EXPECT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + } + } +} + +/* TESTCASE: Tests that the HWC2 cannot set an active config for a bad display */ +TEST_F(Hwc2Test, SET_ACTIVE_CONFIG_bad_display) +{ + hwc2_display_t display; + const hwc2_config_t config = 0; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot set an invalid active config */ +TEST_F(Hwc2Test, SET_ACTIVE_CONFIG_bad_config) +{ + for (auto display : mDisplays) { + hwc2_config_t config; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getInvalidConfig(display, &config)); + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code"; + } +} + +/* TESTCASE: Tests that the HWC2 returns a valid value for getDozeSupport. */ +TEST_F(Hwc2Test, GET_DOZE_SUPPORT) +{ + for (auto display : mDisplays) { + int32_t support = -1; + + ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support)); + + EXPECT_TRUE(support == 0 || support == 1) << "invalid doze support value"; + } +} + +/* TESTCASE: Tests that the HWC2 cannot get doze support for a bad display. */ +TEST_F(Hwc2Test, GET_DOZE_SUPPORT_bad_display) +{ + hwc2_display_t display; + int32_t support = -1; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err)); + + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 can set all supported power modes */ +TEST_F(Hwc2Test, SET_POWER_MODE) +{ + for (auto display : mDisplays) { + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + + int32_t support = -1; + ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support)); + if (support != 1) + return; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE)); + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, + HWC2_POWER_MODE_DOZE_SUSPEND)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } +} + +/* TESTCASE: Tests that the HWC2 cannot set a power mode for a bad display. */ +TEST_F(Hwc2Test, SET_POWER_MODE_bad_display) +{ + hwc2_display_t display; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + + int32_t support = -1; + ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err)); + if (support != 1) + return; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE_SUSPEND, + &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot set an invalid power mode value. */ +TEST_F(Hwc2Test, SET_POWER_MODE_bad_parameter) +{ + for (auto display : mDisplays) { + hwc2_power_mode_t mode = static_cast<hwc2_power_mode_t>( + HWC2_POWER_MODE_DOZE_SUSPEND + 1); + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, mode, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code " + << mode; + } +} + +/* TESTCASE: Tests that the HWC2 will return unsupported if it does not support + * an optional power mode. */ +TEST_F(Hwc2Test, SET_POWER_MODE_unsupported) +{ + for (auto display : mDisplays) { + int32_t support = -1; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err)); + if (support == 1) + return; + + ASSERT_EQ(support, 0) << "invalid doze support value"; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE, + &err)); + EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, + HWC2_POWER_MODE_DOZE_SUSPEND, &err)); + EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code"; + } +} + +/* TESTCASE: Tests that the HWC2 can set the same power mode multiple times. */ +TEST_F(Hwc2Test, SET_POWER_MODE_stress) +{ + for (auto display : mDisplays) { + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + + int32_t support = -1; + ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support)); + if (support != 1) + return; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE)); + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, + HWC2_POWER_MODE_DOZE_SUSPEND)); + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, + HWC2_POWER_MODE_DOZE_SUSPEND)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } +} + +/* TESTCASE: Tests that the HWC2 can enable and disable vsync on active + * displays */ +TEST_F(Hwc2Test, SET_VSYNC_ENABLED) +{ + for (auto display : mDisplays) { + hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>( + const_cast<char*>("data")); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + + ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data, + []() { return; })); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE)); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } +} + +/* TESTCASE: Tests that the HWC2 issues a valid vsync callback. */ +TEST_F(Hwc2Test, SET_VSYNC_ENABLED_callback) +{ + for (auto display : mDisplays) { + hwc2_display_t receivedDisplay; + int64_t receivedTimestamp; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + + ASSERT_NO_FATAL_FAILURE(enableVsync(display)); + + ASSERT_NO_FATAL_FAILURE(waitForVsync(&receivedDisplay, + &receivedTimestamp)); + + EXPECT_EQ(receivedDisplay, display) << "failed to get correct display"; + EXPECT_GE(receivedTimestamp, 0) << "failed to get valid timestamp"; + + ASSERT_NO_FATAL_FAILURE(disableVsync(display)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } +} + +/* TESTCASE: Tests that the HWC2 cannot enable a vsync for a bad display */ +TEST_F(Hwc2Test, SET_VSYNC_ENABLED_bad_display) +{ + hwc2_display_t display; + hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>( + const_cast<char*>("data")); + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data, + []() { return; })); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot enable an invalid vsync value */ +TEST_F(Hwc2Test, SET_VSYNC_ENABLED_bad_parameter) +{ + for (auto display : mDisplays) { + hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>( + const_cast<char*>("data")); + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + + ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data, + []() { return; })); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_INVALID, + &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } +} + +/* TESTCASE: Tests that the HWC2 can enable and disable a vsync value multiple + * times. */ +TEST_F(Hwc2Test, SET_VSYNC_ENABLED_stress) +{ + for (auto display : mDisplays) { + hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>( + const_cast<char*>("data")); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + + ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data, + []() { return; })); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE)); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE)); + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE)); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE)); + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } +} + +/* TESTCASE: Tests that the HWC2 can set a vsync enable value when the display + * is off and no callback is registered. */ +TEST_F(Hwc2Test, SET_VSYNC_ENABLED_no_callback_no_power) +{ + const uint secs = 1; + + for (auto display : mDisplays) { + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE)); + + sleep(secs); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE)); + } +} + +/* TESTCASE: Tests that the HWC2 can set a vsync enable value when no callback + * is registered. */ +TEST_F(Hwc2Test, SET_VSYNC_ENABLED_no_callback) +{ + const uint secs = 1; + + for (auto display : mDisplays) { + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE)); + + sleep(secs); + + ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE)); + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } +} + +/* TESTCASE: Tests that the HWC2 returns a display name for each display */ +TEST_F(Hwc2Test, GET_DISPLAY_NAME) +{ + for (auto display : mDisplays) { + std::string name; + + ASSERT_NO_FATAL_FAILURE(getDisplayName(display, &name)); + } +} + +/* TESTCASE: Tests that the HWC2 does not return a display name for a bad + * display */ +TEST_F(Hwc2Test, GET_DISPLAY_NAME_bad_display) +{ + hwc2_display_t display; + std::string name; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(getDisplayName(display, &name, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 can set basic composition types. */ +TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setComposition, advanceComposition)); +} + +/* TESTCASE: Tests that the HWC2 can update a basic composition type on a + * layer. */ +TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setComposition, advanceComposition)); +} + +/* TESTCASE: Tests that the HWC2 cannot set a composition type for a bad layer */ +TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + setComposition)); +} + +/* TESTCASE: Tests that the HWC2 cannot set a bad composition type */ +TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_bad_parameter) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter( + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + hwc2_error_t* outErr) { + + ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, + layer, HWC2_COMPOSITION_INVALID, outErr)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 can set the cursor position of a layer. */ +TEST_F(Hwc2Test, SET_CURSOR_POSITION) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + ::setCursorPosition, advanceCursorPosition)); +} + +/* TESTCASE: Tests that the HWC2 can update the cursor position of a layer. */ +TEST_F(Hwc2Test, SET_CURSOR_POSITION_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + ::setCursorPosition, advanceCursorPosition)); +} + +/* TESTCASE: Tests that the HWC2 can set the cursor position of a layer when the + * composition type has not been set to HWC2_COMPOSITION_CURSOR. */ +TEST_F(Hwc2Test, SET_CURSOR_POSITION_composition_type_unset) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { + + const hwc_rect_t cursorPosition = testLayer->getCursorPosition(); + EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer, + cursorPosition.left, cursorPosition.top, outErr)); + }, + + advanceCursorPosition)); +} + +/* TESTCASE: Tests that the HWC2 cannot set the cursor position of a bad + * display. */ +TEST_F(Hwc2Test, SET_CURSOR_POSITION_bad_display) +{ + hwc2_display_t display; + hwc2_layer_t layer = 0; + int32_t x = 0, y = 0; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(setCursorPosition(display, layer, x, y, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot set the cursor position of a bad layer. */ +TEST_F(Hwc2Test, SET_CURSOR_POSITION_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { + + const hwc_rect_t cursorPosition = testLayer->getCursorPosition(); + EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, + badLayer, cursorPosition.left, cursorPosition.top, + outErr)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 can set a blend mode value of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setBlendMode, advanceBlendMode)); +} + +/* TESTCASE: Tests that the HWC2 can update a blend mode value of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setBlendMode, advanceBlendMode)); +} + +/* TESTCASE: Tests that the HWC2 cannot set a blend mode for a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + setBlendMode)); +} + +/* TESTCASE: Tests that the HWC2 cannot set an invalid blend mode. */ +TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_bad_parameter) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter( + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + hwc2_error_t* outErr) { + + ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, + layer, HWC2_BLEND_MODE_INVALID, outErr)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 can set the buffer of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_BUFFER) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setBuffer, advanceBuffer)); +} + +/* TESTCASE: Tests that the HWC2 can update the buffer of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_BUFFER_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setBuffer, advanceBuffer)); +} + +/* TESTCASE: Tests that the HWC2 cannot set the buffer of a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { + + buffer_handle_t handle = nullptr; + android::base::unique_fd acquireFence; + + /* If there is not available buffer for the given buffer + * properties, it should not fail this test case */ + if (testLayer->getBuffer(&handle, &acquireFence) == 0) { + *outErr = HWC2_ERROR_BAD_LAYER; + return; + } + + ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, badLayer, + handle, acquireFence, outErr)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 can set an invalid buffer for a layer. */ +TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_parameter) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter( + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + hwc2_error_t* outErr) { + + buffer_handle_t handle = nullptr; + int32_t acquireFence = -1; + + ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer, + handle, acquireFence, outErr)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 can set the color of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_COLOR) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setColor, advanceColor)); +} + +/* TESTCASE: Tests that the HWC2 can update the color of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_COLOR_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setColor, advanceColor)); +} + +/* TESTCASE: Tests that the HWC2 can set the color of a layer when the + * composition type has not been set to HWC2_COMPOSITION_SOLID_COLOR. */ +TEST_F(Hwc2Test, SET_LAYER_COLOR_composition_type_unset) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Basic, + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { + + EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer, + testLayer->getColor(), outErr)); + }, + + advanceColor)); +} + +/* TESTCASE: Tests that the HWC2 cannot set the color of a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_COLOR_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { + + EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, badLayer, + testLayer->getColor(), outErr)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 can set the dataspace of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_DATASPACE) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setDataspace, advanceDataspace)); +} + +/* TESTCASE: Tests that the HWC2 can update the dataspace of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_DATASPACE_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setDataspace, advanceDataspace)); +} + +/* TESTCASE: Tests that the HWC2 cannot set a dataspace for a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_DATASPACE_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + setDataspace)); +} + +/* TESTCASE: Tests that the HWC2 can set the display frame of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setDisplayFrame, advanceDisplayFrame)); +} + +/* TESTCASE: Tests that the HWC2 can update the display frame of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setDisplayFrame, advanceDisplayFrame)); +} + +/* TESTCASE: Tests that the HWC2 cannot set the display frame of a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + setDisplayFrame)); +} + +/* TESTCASE: Tests that the HWC2 can set the plane alpha of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setPlaneAlpha, advancePlaneAlpha)); +} + +/* TESTCASE: Tests that the HWC2 can update the plane alpha of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setPlaneAlpha, advancePlaneAlpha)); +} + +/* TESTCASE: Tests that the HWC2 cannot set a plane alpha for a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer, + Hwc2TestLayer* testLayer, hwc2_error_t *outErr) { + + EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display, + badLayer, testLayer->getPlaneAlpha(), outErr)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 can set the source crop of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setSourceCrop, advanceSourceCrop)); +} + +/* TESTCASE: Tests that the HWC2 can update the source crop of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setSourceCrop, advanceSourceCrop)); +} + +/* TESTCASE: Tests that the HWC2 cannot set the source crop of a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + setSourceCrop)); +} + +/* TESTCASE: Tests that the HWC2 can set the surface damage of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setSurfaceDamage, advanceSurfaceDamage)); +} + +/* TESTCASE: Tests that the HWC2 can update the surface damage of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setSurfaceDamage, advanceSurfaceDamage)); +} + +/* TESTCASE: Tests that the HWC2 cannot set the surface damage of a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + setSurfaceDamage)); +} + +/* TESTCASE: Tests that the HWC2 can set the transform value of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_TRANSFORM) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setTransform, advanceTransform)); +} + +/* TESTCASE: Tests that the HWC2 can update the transform value of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_TRANSFORM_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setTransform, advanceTransform)); +} + +/* TESTCASE: Tests that the HWC2 cannot set the transform for a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_TRANSFORM_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + setTransform)); +} + +/* TESTCASE: Tests that the HWC2 can set the visible region of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_VISIBLE_REGION) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperties(Hwc2TestCoverage::Basic, 5, + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayers* testLayers) { + + EXPECT_NO_FATAL_FAILURE(test->setLayerVisibleRegion(display, + layer, testLayers->getVisibleRegion(layer))); + }, + + advanceVisibleRegions)); +} + +/* TESTCASE: Tests that the HWC2 cannot set the visible region of a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_VISIBLE_REGION_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + setVisibleRegion)); +} + +/* TESTCASE: Tests that the HWC2 can set the z order of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_Z_ORDER) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperties(Hwc2TestCoverage::Complete, 10, + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayers* testLayers) { + + EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer, + testLayers->getZOrder(layer))); + }, + + /* TestLayer z orders are set during the construction of TestLayers + * and cannot be updated. There is no need (or ability) to cycle + * through additional z order configurations. */ + [] (Hwc2TestLayers* /*testLayers*/) { + return false; + } + )); +} + +/* TESTCASE: Tests that the HWC2 can update the z order of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_Z_ORDER_update) +{ + const std::vector<uint32_t> zOrders = { static_cast<uint32_t>(0), + static_cast<uint32_t>(1), static_cast<uint32_t>(UINT32_MAX / 4), + static_cast<uint32_t>(UINT32_MAX / 2), + static_cast<uint32_t>(UINT32_MAX) }; + + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + hwc2_layer_t layer; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + + ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); + + for (uint32_t zOrder : zOrders) { + EXPECT_NO_FATAL_FAILURE(setLayerZOrder(display, layer, zOrder)); + } + + ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); + } + } +} + +/* TESTCASE: Tests that the HWC2 cannot set the z order of a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_Z_ORDER_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + setZOrder)); +} + +/* TESTCASE: Tests that the HWC2 can display a layer with basic property + * coverage */ +TEST_F(Hwc2Test, VALIDATE_DISPLAY_basic) +{ + ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1, + [] (Hwc2Test* test, hwc2_display_t display, + const std::vector<hwc2_layer_t>& layers, + Hwc2TestLayers* /*testLayers*/) { + + uint32_t numTypes, numRequests; + bool hasChanges = false; + + EXPECT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes, + &numRequests, &hasChanges)); + if (hasChanges) + EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size())) + << "wrong number of requests"; + } + )); +} + +/* TESTCASE: Tests that the HWC2 can display 5 layers with default coverage. */ +TEST_F(Hwc2Test, VALIDATE_DISPLAY_default_5) +{ + ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Default, 5, + [] (Hwc2Test* test, hwc2_display_t display, + const std::vector<hwc2_layer_t>& layers, + Hwc2TestLayers* /*testLayers*/) { + + uint32_t numTypes, numRequests; + bool hasChanges = false; + + EXPECT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes, + &numRequests, &hasChanges)); + if (hasChanges) + EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size())) + << "wrong number of requests"; + } + )); +} + +/* TESTCASE: Tests that the HWC2 cannot validate a bad display */ +TEST_F(Hwc2Test, VALIDATE_DISPLAY_bad_display) +{ + hwc2_display_t display; + uint32_t numTypes, numRequests; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, &numRequests, + &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 can get display requests after validating a + * basic layer. */ +TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_basic) +{ + ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1, + [] (Hwc2Test* test, hwc2_display_t display, + const std::vector<hwc2_layer_t>& layers, + Hwc2TestLayers* /*testLayers*/) { + + uint32_t numTypes, numRequests; + bool hasChanges = false; + + ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes, + &numRequests, &hasChanges)); + if (hasChanges) + EXPECT_LE(numTypes, layers.size()) + << "wrong number of requests"; + + EXPECT_NO_FATAL_FAILURE(test->handleRequests(display, layers, + numRequests)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 cannot get display requests from a bad display */ +TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_bad_display) +{ + hwc2_display_t display; + hwc2_display_request_t displayRequests; + std::vector<hwc2_layer_t> layers; + std::vector<hwc2_layer_request_t> layerRequests; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + EXPECT_NO_FATAL_FAILURE(getDisplayRequests(display, &displayRequests, + &layers, &layerRequests, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot get display requests from an non + * validated display. */ +TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_not_validated) +{ + ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5, + [] (Hwc2Test* test, hwc2_display_t display, + std::vector<hwc2_layer_t>* layers) { + + hwc2_display_request_t displayRequests; + std::vector<hwc2_layer_request_t> layerRequests; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->getDisplayRequests(display, + &displayRequests, layers, &layerRequests, &err)); + EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED) + << "returned wrong error code"; + } + )); +} + +/* TESTCASE: Tests that the HWC2 can get changed composition types after + * validating a basic layer. */ +TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_basic) +{ + ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1, + [] (Hwc2Test* test, hwc2_display_t display, + const std::vector<hwc2_layer_t>& layers, + Hwc2TestLayers* testLayers) { + + uint32_t numTypes, numRequests; + bool hasChanges = false; + + ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes, + &numRequests, &hasChanges)); + if (hasChanges) + EXPECT_LE(numTypes, layers.size()) + << "wrong number of requests"; + + EXPECT_NO_FATAL_FAILURE(test->handleCompositionChanges(display, + *testLayers, layers, numTypes)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 cannot get changed composition types from a bad + * display */ +TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_bad_display) +{ + hwc2_display_t display; + std::vector<hwc2_layer_t> layers; + std::vector<hwc2_composition_t> types; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + EXPECT_NO_FATAL_FAILURE(getChangedCompositionTypes(display, &layers, + &types, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot get changed composition types from an non + * validated display. */ +TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_not_validated) +{ + ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5, + [] (Hwc2Test* test, hwc2_display_t display, + std::vector<hwc2_layer_t>* layers) { + + std::vector<hwc2_composition_t> types; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->getChangedCompositionTypes( + display, layers, &types, &err)); + EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED) + << "returned wrong error code"; + } + )); +} + +/* TESTCASE: Tests that the HWC2 can accept display changes after validating a + * basic layer. */ +TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_basic) +{ + ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1, + [] (Hwc2Test* test, hwc2_display_t display, + const std::vector<hwc2_layer_t>& layers, + Hwc2TestLayers* testLayers) { + + uint32_t numTypes, numRequests; + bool hasChanges = false; + + ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes, + &numRequests, &hasChanges)); + if (hasChanges) + EXPECT_LE(numTypes, layers.size()) + << "wrong number of requests"; + + ASSERT_NO_FATAL_FAILURE(test->handleCompositionChanges(display, + *testLayers, layers, numTypes)); + + EXPECT_NO_FATAL_FAILURE(test->acceptDisplayChanges(display)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 cannot accept display changes from a bad + * display */ +TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_bad_display) +{ + hwc2_display_t display; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + EXPECT_NO_FATAL_FAILURE(acceptDisplayChanges(display, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot accept display changes from an non + * validated display. */ +TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_not_validated) +{ + ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5, + [] (Hwc2Test* test, hwc2_display_t display, + std::vector<hwc2_layer_t>* /*layers*/) { + + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->acceptDisplayChanges(display, &err)); + EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED) + << "returned wrong error code"; + } + )); +} + +/* TESTCASE: Tests that the HWC2 supports client target with required values */ +TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT) +{ + ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Default, + [] (Hwc2Test* test, hwc2_display_t display, + const Hwc2TestClientTargetSupport& testClientTargetSupport) { + + const Area bufferArea = testClientTargetSupport.getBufferArea(); + const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888; + + ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(display, + bufferArea.width, bufferArea.height, format, + testClientTargetSupport.getDataspace())); + }, + + advanceClientTargetSupport)); +} + +/* TESTCASE: Tests that the HWC2 cannot get client target support for a bad + * display. */ +TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT_bad_display) +{ + ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Default, + [] (Hwc2Test* test, hwc2_display_t /*display*/, + const Hwc2TestClientTargetSupport& testClientTargetSupport) { + + const Area bufferArea = testClientTargetSupport.getBufferArea(); + const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888; + hwc2_display_t badDisplay; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay)); + + ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(badDisplay, + bufferArea.width, bufferArea.height, format, + testClientTargetSupport.getDataspace(), &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; + }, + + advanceClientTargetSupport)); +} + +/* TESTCASE: Tests that the HWC2 either supports or returns error unsupported + * for a variety of client target values. */ +TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT_unsupported) +{ + ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Complete, + [] (Hwc2Test* test, hwc2_display_t display, + const Hwc2TestClientTargetSupport& testClientTargetSupport) { + + const Area bufferArea = testClientTargetSupport.getBufferArea(); + const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(display, + bufferArea.width, bufferArea.height, format, + testClientTargetSupport.getDataspace(), &err)); + EXPECT_TRUE(err == HWC2_ERROR_NONE + || err == HWC2_ERROR_UNSUPPORTED) + << "returned wrong error code"; + }, + + advanceClientTargetSupport)); +} + +/* TESTCASE: Tests that the HWC2 can set a client target buffer for a basic + * layer. */ +TEST_F(Hwc2Test, SET_CLIENT_TARGET_basic) +{ + const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; + const hwc_region_t damage = { }; + const size_t layerCnt = 1; + + for (auto display : mDisplays) { + std::vector<hwc2_config_t> configs; + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); + + ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); + + for (auto config : configs) { + Area displayArea; + std::vector<hwc2_layer_t> layers; + + ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); + ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea)); + + ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt)); + Hwc2TestLayers testLayers(layers, Hwc2TestCoverage::Basic, + displayArea); + + if (!testLayers.optimizeLayouts()) + continue; + + Hwc2TestClientTarget testClientTarget; + + do { + std::set<hwc2_layer_t> clientLayers; + std::set<hwc2_layer_t> clearLayers; + uint32_t numTypes, numRequests; + bool hasChanges, skip; + bool flipClientTarget; + buffer_handle_t handle; + int32_t acquireFence; + + ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers, + &testLayers, &skip)); + if (skip) + continue; + + ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, + &numRequests, &hasChanges)); + if (hasChanges) + EXPECT_LE(numTypes, layers.size()) + << "wrong number of requests"; + + ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display, + testLayers, layers, numTypes, &clientLayers)); + ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers, + numRequests, &clearLayers, &flipClientTarget)); + ASSERT_EQ(testClientTarget.getBuffer(testLayers, clientLayers, + clearLayers, flipClientTarget, displayArea, &handle, + &acquireFence), 0); + EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle, + acquireFence, dataspace, damage)); + + if (acquireFence >= 0) + close(acquireFence); + + } while (testLayers.advance()); + + ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers))); + } + + ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); + } +} + +/* TESTCASE: Tests that the HWC2 cannot set a client target for a bad display. */ +TEST_F(Hwc2Test, SET_CLIENT_TARGET_bad_display) +{ + hwc2_display_t display; + std::vector<hwc2_layer_t> layers; + const Area displayArea = {0, 0}; + Hwc2TestLayers testLayers(layers, Hwc2TestCoverage::Default, displayArea); + std::set<hwc2_layer_t> clientLayers; + std::set<hwc2_layer_t> flipClientTargetLayers; + bool flipClientTarget = true; + const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; + const hwc_region_t damage = { }; + buffer_handle_t handle; + int32_t acquireFence; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + Hwc2TestClientTarget testClientTarget; + + ASSERT_EQ(testClientTarget.getBuffer(testLayers, clientLayers, + flipClientTargetLayers, flipClientTarget, displayArea, &handle, + &acquireFence), 0); + + EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle, acquireFence, + dataspace, damage, &err)); + + if (acquireFence >= 0) + close(acquireFence); + + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 can present 1 default layer. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_default_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 2 default layers. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_default_2) +{ + const size_t layerCnt = 2; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 3 default layers. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_default_3) +{ + const size_t layerCnt = 3; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 4 default layers. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_default_4) +{ + const size_t layerCnt = 4; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 5 default layers. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_default_5) +{ + const size_t layerCnt = 5; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 6 default layers. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_default_6) +{ + const size_t layerCnt = 6; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * blend mode. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_blend_mode_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Basic}, + {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic}}; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of + * blend mode. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_blend_mode_2) +{ + const size_t layerCnt = 2; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic}}; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * buffer. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_buffer_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * color. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_color_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::Color, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of + * color. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_color_2) +{ + const size_t layerCnt = 2; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic}, + {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic}, + {Hwc2TestPropertyName::Color, Hwc2TestCoverage::Basic}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * composition. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_composition_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * cursor. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_cursor_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::CursorPosition, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of + * cursor. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_cursor_2) +{ + const size_t layerCnt = 2; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::CursorPosition, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Basic}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * dataspace. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_dataspace_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * display frame. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of + * display frame. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_2) +{ + const size_t layerCnt = 2; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 3 layers with complete coverage of + * display frame. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_3) +{ + const size_t layerCnt = 3; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 4 layers with complete coverage of + * display frame. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_4) +{ + const size_t layerCnt = 4; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * plane alpha. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_plane_alpha_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic}, + {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Complete}}; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of + * plane alpha. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_plane_alpha_2) +{ + const size_t layerCnt = 2; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic}, + {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Complete}}; + bool optimize = false; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * source crop. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_source_crop_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::SourceCrop, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of + * source crop. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_source_crop_2) +{ + const size_t layerCnt = 2; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::SourceCrop, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * surface damage. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_surface_damage_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::SurfaceDamage, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * transform. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_transform_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Complete}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of + * transform. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_transform_2) +{ + const size_t layerCnt = 2; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions = + {{Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Complete}, + {Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Basic}}; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of + * basic. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_basic_1) +{ + const size_t layerCnt = 1; + Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic; + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions; + bool optimize = true; + + ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions, + optimize)); +} + +/* TESTCASE: Tests that the HWC2 cannot present a bad display. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_bad_display) +{ + hwc2_display_t display; + int32_t presentFence; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(presentDisplay(display, &presentFence, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot present an unvalidated display. */ +TEST_F(Hwc2Test, PRESENT_DISPLAY_not_validated) +{ + ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Default, 1, + [] (Hwc2Test* test, hwc2_display_t display, + const std::vector<hwc2_layer_t>& /*layers*/, + Hwc2TestLayers* /*testLayers*/) { + + int32_t presentFence; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->setPowerMode(display, + HWC2_POWER_MODE_ON)); + ASSERT_NO_FATAL_FAILURE(test->enableVsync(display)); + + ASSERT_NO_FATAL_FAILURE(test->waitForVsync()); + + ASSERT_NO_FATAL_FAILURE(test->presentDisplay(display, + &presentFence, &err)); + EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED) + << "returned wrong error code"; + + ASSERT_NO_FATAL_FAILURE(test->disableVsync(display)); + ASSERT_NO_FATAL_FAILURE(test->setPowerMode(display, + HWC2_POWER_MODE_OFF)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 cannot get release fences from a bad display. */ +TEST_F(Hwc2Test, GET_RELEASE_FENCES_bad_display) +{ + hwc2_display_t display; + std::vector<hwc2_layer_t> layers; + std::vector<int32_t> fences; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(getReleaseFences(display, &layers, &fences, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +static const std::array<android_color_mode, 9> androidColorModes = {{ + HAL_COLOR_MODE_NATIVE, + HAL_COLOR_MODE_STANDARD_BT601_625, + HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED, + HAL_COLOR_MODE_STANDARD_BT601_525, + HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED, + HAL_COLOR_MODE_STANDARD_BT709, + HAL_COLOR_MODE_DCI_P3, + HAL_COLOR_MODE_SRGB, + HAL_COLOR_MODE_ADOBE_RGB, +}}; + +/* TESTCASE: Tests that the HWC2 can get the color modes for a display. The + * display must support HAL_COLOR_MODE_NATIVE */ +TEST_F(Hwc2Test, GET_COLOR_MODES) +{ + ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig( + [] (Hwc2Test* test, hwc2_display_t display) { + + std::vector<android_color_mode_t> colorModes; + + ASSERT_NO_FATAL_FAILURE(test->getColorModes(display, + &colorModes)); + + EXPECT_NE(std::count(colorModes.begin(), colorModes.end(), + HAL_COLOR_MODE_NATIVE), 0) << "all displays" + " must support HAL_COLOR_MODE_NATIVE"; + } + )); +} + +/* TESTCASE: Tests that the HWC2 cannot get color modes from a bad display. */ +TEST_F(Hwc2Test, GET_COLOR_MODES_bad_display) +{ + hwc2_display_t display; + std::vector<android_color_mode_t> colorModes; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(getColorModes(display, &colorModes, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 can set the required color mode on a display. */ +TEST_F(Hwc2Test, SET_COLOR_MODES) +{ + ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig( + [] (Hwc2Test* test, hwc2_display_t display) { + + const android_color_mode_t colorMode = HAL_COLOR_MODE_NATIVE; + + EXPECT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 cannot set a color mode on a bad display. */ +TEST_F(Hwc2Test, SET_COLOR_MODES_bad_display) +{ + hwc2_display_t display; + const android_color_mode_t colorMode = HAL_COLOR_MODE_NATIVE; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(setColorMode(display, colorMode, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot set an invalid color mode. */ +TEST_F(Hwc2Test, SET_COLOR_MODES_bad_parameter) +{ + ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig( + [] (Hwc2Test* test, hwc2_display_t display) { + + const android_color_mode_t colorMode = + static_cast<android_color_mode_t>(-1); + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode, + &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) + << "returned wrong error code"; + } + )); +} + +/* TESTCASE: Tests that the HWC2 either supports or returns error unsupported + * for all valid color modes. */ +TEST_F(Hwc2Test, SET_COLOR_MODES_unsupported) +{ + ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig( + [] (Hwc2Test* test, hwc2_display_t display) { + + for (auto colorMode : androidColorModes) { + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->setColorMode(display, + colorMode, &err)); + + EXPECT_TRUE(err == HWC2_ERROR_NONE + || err == HWC2_ERROR_UNSUPPORTED) + << "returned wrong error code"; + } + } + )); +} + +/* TESTCASE: Tests that the HWC2 gets the HDR capabilities for a display and + * test if they are valid. */ +TEST_F(Hwc2Test, GET_HDR_CAPABILITIES) +{ + ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig( + [] (Hwc2Test* test, hwc2_display_t display) { + + std::vector<android_hdr_t> hdrCapabilities; + float maxLuminance, maxAverageLuminance, minLuminance; + + EXPECT_NO_FATAL_FAILURE(test->getHdrCapabilities(display, + &hdrCapabilities, &maxLuminance, &maxAverageLuminance, + &minLuminance)); + + if (hdrCapabilities.empty()) + return; + + EXPECT_GE(maxLuminance, maxAverageLuminance); + EXPECT_GE(maxAverageLuminance, minLuminance); + } + )); +} + +/* TESTCASE: Tests that the HWC2 cannot get hdr capabilities from a bad display */ +TEST_F(Hwc2Test, GET_HDR_CAPABILITIES_bad_display) +{ + hwc2_display_t display; + std::vector<android_hdr_t> hdrCapabilities; + float maxLuminance, maxAverageLuminance, minLuminance; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(getHdrCapabilities(display, &hdrCapabilities, + &maxLuminance, &maxAverageLuminance, &minLuminance, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +static const std::array<float, 16> identityMatrix = {{ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, +}}; + +/* Values for the color transform matrices were precomputed using the source code + * in surfaceflinger/Effects/Daltonizer.cpp. */ + +static const std::array<const std::array<float, 16>, 5> exampleMatrices = {{ + identityMatrix, + /* Converts RGB color to the XYZ space */ + {{ 0.4124, 0.2126, 0.0193, 0, + 0.3576, 0.7152, 0.1192, 0, + 0.1805, 0.0722, 0.9505, 0, + 0 , 0 , 0 , 1 }}, + /* Protanomaly */ + {{ 0.068493, 0.931506, 0, 0, + 0.068493, 0.931507, 0, 0, + 0.013626, -0.013626, 1, 0, + 0, 0, 0, 1 }}, + /* Deuteranomaly */ + {{ 0.288299, 0.711701, 0, 0, + 0.052709, 0.947291, 0, 0, + -0.257912, 0.257912, 1, 0, + 0, 0, 0, 1 }}, + /* Tritanomaly */ + {{ 1, -0.805712, 0.805712, 0, + 0, 0.378838, 0.621162, 0, + 0, 0.104823, 0.895177, 0, + 0, 0, 0, 1 }}, +}}; + +/* TESTCASE: Tests that the HWC2 can set the identity color transform */ +TEST_F(Hwc2Test, SET_COLOR_TRANSFORM) +{ + ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig( + [] (Hwc2Test* test, hwc2_display_t display) { + + EXPECT_NO_FATAL_FAILURE(test->setColorTransform(display, + identityMatrix, HAL_COLOR_TRANSFORM_IDENTITY)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 cannot set the color transform for a bad + * display. */ +TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_bad_display) +{ + hwc2_display_t display; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(setColorTransform(display, identityMatrix, + HAL_COLOR_TRANSFORM_IDENTITY, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot set an invalid color transform. */ +TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_bad_parameter) +{ + ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig( + [] (Hwc2Test* test, hwc2_display_t display) { + + const android_color_transform_t hint = + static_cast<android_color_transform_t>(-1); + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->setColorTransform(display, + identityMatrix, hint, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) + << "returned wrong error code"; + } + )); +} + +/* TESTCASE: Tests that the HWC2 can set an arbitrary color matrix. */ +TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_arbitrary_matrix) +{ + ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig( + [] (Hwc2Test* test, hwc2_display_t display) { + + const android_color_transform_t hint = + HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX; + + for (const std::array<float, 16>& matrix : exampleMatrices) { + EXPECT_NO_FATAL_FAILURE(test->setColorTransform(display, + matrix, hint)); + } + } + )); +} + +/* TESTCASE: Tests that the HWC2 create an destory virtual displays. */ +TEST_F(Hwc2Test, CREATE_DESTROY_VIRTUAL_DISPLAY) +{ + ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Complete, + [] (Hwc2Test* /*test*/, hwc2_display_t /*display*/, + Hwc2TestVirtualDisplay* /*testVirtualDisplay*/) { })); +} + +/* TESTCASE: Tests that the HWC2 can create and destroy multiple virtual + * displays. */ +TEST_F(Hwc2Test, CREATE_DESTROY_VIRTUAL_DISPLAY_multiple) +{ + Hwc2TestVirtualDisplay testVirtualDisplay(Hwc2TestCoverage::Complete); + std::vector<hwc2_display_t> displays; + + do { + const UnsignedArea& dimension = + testVirtualDisplay.getDisplayDimension(); + android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888; + hwc2_display_t display; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width, + dimension.height, &desiredFormat, &display, &err)); + + EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_NO_RESOURCES + || err == HWC2_ERROR_UNSUPPORTED) << "returned wrong error code"; + EXPECT_GE(desiredFormat, 0) << "invalid format"; + + if (err == HWC2_ERROR_NONE) + displays.push_back(display); + + } while (testVirtualDisplay.advance()); + + for (hwc2_display_t display : displays) { + EXPECT_NO_FATAL_FAILURE(destroyVirtualDisplay(display)); + } +} + +/* TESTCASE: Tests that the HWC2 cannot destroy a bad virtual displays. */ +TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_display) +{ + hwc2_display_t display; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display)); + + ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 cannot destroy a physical display. */ +TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_parameter) +{ + hwc2_display_t display = HWC_DISPLAY_PRIMARY; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code"; +} + +/* TESTCASE: Tests that the HWC2 can get the max virtual display count. */ +TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT) +{ + uint32_t maxCnt; + + ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt)); +} + +/* TESTCASE: Tests that the HWC2 returns the same max virtual display count for + * each call. */ +TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT_duplicate) +{ + uint32_t maxCnt1, maxCnt2; + + ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt1)); + ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt2)); + + EXPECT_EQ(maxCnt1, maxCnt2) << "returned two different max virtual display" + " counts"; +} + +/* TESTCASE: Tests that the HWC2 can create the max number of virtual displays + * that it reports. */ +TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT_create_max) +{ + std::vector<hwc2_display_t> displays; + uint32_t maxCnt; + + ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt)); + + while (displays.size() < maxCnt) { + uint32_t width = 1920, height = 1080; + android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888; + hwc2_display_t display; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(width, height, + &desiredFormat, &display, &err)); + + EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_UNSUPPORTED) + << "returned wrong error code"; + if (err != HWC2_ERROR_NONE) + break; + + displays.push_back(display); + } + + for (hwc2_display_t display : displays) { + EXPECT_NO_FATAL_FAILURE(destroyVirtualDisplay(display)); + } +} + +/* TESTCASE: Tests that the HWC2 can set an output buffer for a virtual + * display. */ +TEST_F(Hwc2Test, SET_OUTPUT_BUFFER) +{ + ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Complete, + [] (Hwc2Test* test, hwc2_display_t display, + Hwc2TestVirtualDisplay* testVirtualDisplay) { + + buffer_handle_t handle; + android::base::unique_fd acquireFence; + + if (testVirtualDisplay->getBuffer(&handle, &acquireFence) >= 0) + EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display, + handle, acquireFence)); + })); +} + +/* TESTCASE: Tests that the HWC2 cannot set an output buffer for a bad display */ +TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_display) +{ + ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Default, + [] (Hwc2Test* test, hwc2_display_t /*display*/, + Hwc2TestVirtualDisplay* testVirtualDisplay) { + + hwc2_display_t badDisplay; + buffer_handle_t handle; + android::base::unique_fd acquireFence; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay)); + + if (testVirtualDisplay->getBuffer(&handle, &acquireFence) < 0) + return; + + ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay, + handle, acquireFence, &err)); + EXPECT_TRUE(err == HWC2_ERROR_BAD_DISPLAY) + << "returned wrong error code"; + })); +} + +/* TESTCASE: Tests that the HWC2 cannot set an invalid output buffer. */ +TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_parameter) +{ + ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Default, + [] (Hwc2Test* test, hwc2_display_t display, + Hwc2TestVirtualDisplay* /*testVirtualDisplay*/) { + + const buffer_handle_t handle = nullptr; + uint32_t releaseFence = -1; + hwc2_error_t err = HWC2_ERROR_NONE; + + ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(display, handle, + releaseFence, &err)); + EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) + << "returned wrong error code"; + })); +} + +/* TESTCASE: Tests that the HWC2 cannot set an output buffer for non virtual + * display */ +TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_unsupported) +{ + for (auto display : mDisplays) { + Hwc2TestVirtualDisplay testVirtualDisplay(Hwc2TestCoverage::Complete); + + do { + buffer_handle_t handle; + android::base::unique_fd acquireFence; + hwc2_error_t err = HWC2_ERROR_NONE; + + if (testVirtualDisplay.getBuffer(&handle, &acquireFence) < 0) + continue; + + ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle, + acquireFence, &err)); + EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code"; + + } while (testVirtualDisplay.advance()); + } +} + +/* TESTCASE: Tests that the HWC2 can dump debug information. */ +TEST_F(Hwc2Test, DUMP) +{ + std::string buffer; + + ASSERT_NO_FATAL_FAILURE(dump(&buffer)); +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp new file mode 100644 index 0000000000..a59f388a66 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp @@ -0,0 +1,692 @@ +/* + * Copyright (C) 2016 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 <mutex> +#include <array> +#include <sstream> +#include <algorithm> + +#include <gui/Surface.h> +#include <gui/BufferItemConsumer.h> +#include <gui/GraphicBufferAlloc.h> + +#include <ui/GraphicBuffer.h> +#include <ui/vec4.h> + +#include <GLES3/gl3.h> + +#include "Hwc2TestBuffer.h" +#include "Hwc2TestLayers.h" + +using namespace android; + +/* Returns a fence from egl */ +typedef void (*FenceCallback)(int32_t fence, void* callbackArgs); + +/* Returns fence to fence generator */ +static void setFence(int32_t fence, void* fenceGenerator); + + +/* Used to receive the surfaces and fences from egl. The egl buffers are thrown + * away. The fences are sent to the requester via a callback */ +class Hwc2TestSurfaceManager { +public: + /* Listens for a new frame, detaches the buffer and returns the fence + * through saved callback. */ + class BufferListener : public ConsumerBase::FrameAvailableListener { + public: + BufferListener(sp<IGraphicBufferConsumer> consumer, + FenceCallback callback, void* callbackArgs) + : mConsumer(consumer), + mCallback(callback), + mCallbackArgs(callbackArgs) { } + + void onFrameAvailable(const BufferItem& /*item*/) + { + BufferItem item; + + if (mConsumer->acquireBuffer(&item, 0)) + return; + if (mConsumer->detachBuffer(item.mSlot)) + return; + + mCallback(item.mFence->dup(), mCallbackArgs); + } + + private: + sp<IGraphicBufferConsumer> mConsumer; + FenceCallback mCallback; + void* mCallbackArgs; + }; + + /* Creates a buffer listener that waits on a new frame from the buffer + * queue. */ + void initialize(const Area& bufferArea, android_pixel_format_t format, + FenceCallback callback, void* callbackArgs) + { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + consumer->setDefaultBufferSize(bufferArea.width, bufferArea.height); + consumer->setDefaultBufferFormat(format); + + mBufferItemConsumer = new BufferItemConsumer(consumer, 0); + + mListener = new BufferListener(consumer, callback, callbackArgs); + mBufferItemConsumer->setFrameAvailableListener(mListener); + + mSurface = new Surface(producer, true); + } + + /* Used by Egl manager. The surface is never displayed. */ + sp<Surface> getSurface() const + { + return mSurface; + } + +private: + sp<BufferItemConsumer> mBufferItemConsumer; + sp<BufferListener> mListener; + /* Used by Egl manager. The surface is never displayed */ + sp<Surface> mSurface; +}; + + +/* Used to generate valid fences. It is not possible to create a dummy sync + * fence for testing. Egl can generate buffers along with a valid fence. + * The buffer cannot be guaranteed to be the same format across all devices so + * a CPU filled buffer is used instead. The Egl fence is used along with the + * CPU filled buffer. */ +class Hwc2TestEglManager { +public: + Hwc2TestEglManager() + : mEglDisplay(EGL_NO_DISPLAY), + mEglSurface(EGL_NO_SURFACE), + mEglContext(EGL_NO_CONTEXT) { } + + ~Hwc2TestEglManager() + { + cleanup(); + } + + int initialize(sp<Surface> surface) + { + mSurface = surface; + + mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (mEglDisplay == EGL_NO_DISPLAY) return false; + + EGLint major; + EGLint minor; + if (!eglInitialize(mEglDisplay, &major, &minor)) { + ALOGW("Could not initialize EGL"); + return false; + } + + /* We're going to use a 1x1 pbuffer surface later on + * The configuration distance doesn't really matter for what we're + * trying to do */ + EGLint configAttrs[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 0, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 0, + EGL_NONE + }; + + EGLConfig configs[1]; + EGLint configCnt; + if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1, + &configCnt)) { + ALOGW("Could not select EGL configuration"); + eglReleaseThread(); + eglTerminate(mEglDisplay); + return false; + } + + if (configCnt <= 0) { + ALOGW("Could not find EGL configuration"); + eglReleaseThread(); + eglTerminate(mEglDisplay); + return false; + } + + /* These objects are initialized below but the default "null" values are + * used to cleanup properly at any point in the initialization sequence */ + EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT, + attrs); + if (mEglContext == EGL_NO_CONTEXT) { + ALOGW("Could not create EGL context"); + cleanup(); + return false; + } + + EGLint surfaceAttrs[] = { EGL_NONE }; + mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0], + mSurface.get(), surfaceAttrs); + if (mEglSurface == EGL_NO_SURFACE) { + ALOGW("Could not create EGL surface"); + cleanup(); + return false; + } + + if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + ALOGW("Could not change current EGL context"); + cleanup(); + return false; + } + + return true; + } + + void makeCurrent() const + { + eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); + } + + void present() const + { + eglSwapBuffers(mEglDisplay, mEglSurface); + } + +private: + void cleanup() + { + if (mEglDisplay == EGL_NO_DISPLAY) + return; + if (mEglSurface != EGL_NO_SURFACE) + eglDestroySurface(mEglDisplay, mEglSurface); + if (mEglContext != EGL_NO_CONTEXT) + eglDestroyContext(mEglDisplay, mEglContext); + + eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + eglReleaseThread(); + eglTerminate(mEglDisplay); + } + + sp<Surface> mSurface; + EGLDisplay mEglDisplay; + EGLSurface mEglSurface; + EGLContext mEglContext; +}; + + +static const std::array<vec2, 4> triangles = {{ + { 1.0f, 1.0f }, + { -1.0f, 1.0f }, + { 1.0f, -1.0f }, + { -1.0f, -1.0f }, +}}; + +class Hwc2TestFenceGenerator { +public: + + Hwc2TestFenceGenerator() + { + mSurfaceManager.initialize({1, 1}, HAL_PIXEL_FORMAT_RGBA_8888, + setFence, this); + + if (!mEglManager.initialize(mSurfaceManager.getSurface())) + return; + + mEglManager.makeCurrent(); + + glClearColor(0.0, 0.0, 0.0, 1.0); + glEnableVertexAttribArray(0); + } + + ~Hwc2TestFenceGenerator() + { + if (mFence >= 0) + close(mFence); + mFence = -1; + + mEglManager.makeCurrent(); + } + + /* It is not possible to simply generate a fence. The easiest way is to + * generate a buffer using egl and use the associated fence. The buffer + * cannot be guaranteed to be a certain format across all devices using this + * method. Instead the buffer is generated using the CPU */ + int32_t get() + { + if (mFence >= 0) { + return dup(mFence); + } + + std::unique_lock<std::mutex> lock(mMutex); + + /* If the pending is still set to false and times out, we cannot recover. + * Set an error and return */ + while (mPending != false) { + if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout) + return -ETIME; + } + + /* Generate a fence. The fence will be returned through the setFence + * callback */ + mEglManager.makeCurrent(); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, triangles.data()); + glClear(GL_COLOR_BUFFER_BIT); + + mEglManager.present(); + + /* Wait for the setFence callback */ + while (mPending != true) { + if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout) + return -ETIME; + } + + mPending = false; + + return dup(mFence); + } + + /* Callback that sets the fence */ + void set(int32_t fence) + { + mFence = fence; + mPending = true; + + mCv.notify_all(); + } + +private: + + Hwc2TestSurfaceManager mSurfaceManager; + Hwc2TestEglManager mEglManager; + + std::mutex mMutex; + std::condition_variable mCv; + + int32_t mFence = -1; + bool mPending = false; +}; + + +static void setFence(int32_t fence, void* fenceGenerator) +{ + static_cast<Hwc2TestFenceGenerator*>(fenceGenerator)->set(fence); +} + + +/* Sets the pixel of a buffer given the location, format, stride and color. + * Currently only supports RGBA_8888 */ +static void setColor(int32_t x, int32_t y, + android_pixel_format_t format, uint32_t stride, uint8_t* img, uint8_t r, + uint8_t g, uint8_t b, uint8_t a) +{ + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + img[(y * stride + x) * 4 + 0] = r; + img[(y * stride + x) * 4 + 1] = g; + img[(y * stride + x) * 4 + 2] = b; + img[(y * stride + x) * 4 + 3] = a; + break; + default: + break; + } +} + +Hwc2TestBuffer::Hwc2TestBuffer() + : mFenceGenerator(new Hwc2TestFenceGenerator()) { } + +Hwc2TestBuffer::~Hwc2TestBuffer() = default; + +/* When the buffer changes sizes, save the new size and invalidate the current + * buffer */ +void Hwc2TestBuffer::updateBufferArea(const Area& bufferArea) +{ + if (mBufferArea.width == bufferArea.width + && mBufferArea.height == bufferArea.height) + return; + + mBufferArea.width = bufferArea.width; + mBufferArea.height = bufferArea.height; + + mValidBuffer = false; +} + +/* Returns a valid buffer handle and fence. The handle is filled using the CPU + * to ensure the correct format across all devices. The fence is created using + * egl. */ +int Hwc2TestBuffer::get(buffer_handle_t* outHandle, int32_t* outFence) +{ + if (mBufferArea.width == -1 || mBufferArea.height == -1) + return -EINVAL; + + /* If the current buffer is valid, the previous buffer can be reused. + * Otherwise, create new buffer */ + if (!mValidBuffer) { + int ret = generateBuffer(); + if (ret) + return ret; + } + + *outFence = mFenceGenerator->get(); + *outHandle = mHandle; + + mValidBuffer = true; + + return 0; +} + +/* CPU fills a buffer to guarantee the correct buffer format across all + * devices */ +int Hwc2TestBuffer::generateBuffer() +{ + int ret; + + /* Create new graphic buffer with correct dimensions */ + mGraphicBuffer = mGraphicBufferAlloc.createGraphicBuffer( + mBufferArea.width, mBufferArea.height, mFormat, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER, + "hwc2_test_buffer", &ret); + if (ret) + return ret; + + /* Locks the buffer for writing */ + uint8_t* img; + mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + + uint32_t stride = mGraphicBuffer->getStride(); + + /* Iterate from the top row of the buffer to the bottom row */ + for (int32_t y = 0; y < mBufferArea.height; y++) { + + /* Will be used as R, G and B values for pixel colors */ + uint8_t max = 255; + uint8_t min = 0; + + /* Divide the rows into 3 sections. The first section will contain + * the lighest colors. The last section will contain the darkest + * colors. */ + if (y < mBufferArea.height * 1.0 / 3.0) { + min = 255 / 2; + } else if (y >= mBufferArea.height * 2.0 / 3.0) { + max = 255 / 2; + } + + /* Divide the columns into 3 sections. The first section is red, + * the second is green and the third is blue */ + int32_t x = 0; + for (; x < mBufferArea.width / 3; x++) { + setColor(x, y, mFormat, stride, img, max, min, min, 255); + } + + for (; x < mBufferArea.width * 2 / 3; x++) { + setColor(x, y, mFormat, stride, img, min, max, min, 255); + } + + for (; x < mBufferArea.width; x++) { + setColor(x, y, mFormat, stride, img, min, min, max, 255); + } + } + + /* Unlock the buffer for reading */ + mGraphicBuffer->unlock(); + + mHandle = mGraphicBuffer->handle; + + return 0; +} + + +Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer() + : mFenceGenerator(new Hwc2TestFenceGenerator()) { } + +Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { } + +/* Generates a client target buffer using the layers assigned for client + * composition. Takes into account the individual layer properties such as + * transform, blend mode, source crop, etc. */ +int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, + int32_t* outFence, const Area& bufferArea, + const Hwc2TestLayers* testLayers, + const std::set<hwc2_layer_t>* clientLayers, + const std::set<hwc2_layer_t>* clearLayers) +{ + int err; + + /* Create new graphic buffer with updated size */ + mGraphicBuffer = mGraphicBufferAlloc.createGraphicBuffer(bufferArea.width, + bufferArea.height, mFormat, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER, + "hwc2_test_buffer", &err); + if (err) + return err; + + uint8_t* img; + mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + + uint32_t stride = mGraphicBuffer->getStride(); + + float bWDiv3 = bufferArea.width / 3; + float bW2Div3 = bufferArea.width * 2 / 3; + float bHDiv3 = bufferArea.height / 3; + float bH2Div3 = bufferArea.height * 2 / 3; + + /* Cycle through every pixel in the buffer and determine what color it + * should be. */ + for (int32_t y = 0; y < bufferArea.height; y++) { + for (int32_t x = 0; x < bufferArea.width; x++) { + + uint8_t r = 0, g = 0, b = 0; + float a = 0.0f; + + /* Cycle through each client layer from back to front and + * update the pixel color. */ + for (auto layer = clientLayers->rbegin(); + layer != clientLayers->rend(); ++layer) { + + const hwc_rect_t df = testLayers->getDisplayFrame(*layer); + + float dfL = df.left; + float dfT = df.top; + float dfR = df.right; + float dfB = df.bottom; + + /* If the pixel location falls outside of the layer display + * frame, skip the layer. */ + if (x < dfL || x >= dfR || y < dfT || y >= dfB) + continue; + + /* If the device has requested the layer be clear, clear + * the pixel and continue. */ + if (clearLayers->count(*layer) != 0) { + r = 0; + g = 0; + b = 0; + a = 0.0f; + continue; + } + + float planeAlpha = testLayers->getPlaneAlpha(*layer); + + /* If the layer is a solid color, fill the color and + * continue. */ + if (testLayers->getComposition(*layer) + == HWC2_COMPOSITION_SOLID_COLOR) { + const auto color = testLayers->getColor(*layer); + r = color.r; + g = color.g; + b = color.b; + a = color.a * planeAlpha; + continue; + } + + float xPos = x; + float yPos = y; + + hwc_transform_t transform = testLayers->getTransform(*layer); + + float dfW = dfR - dfL; + float dfH = dfB - dfT; + + /* If a layer has a transform, find which location on the + * layer will end up in the current pixel location. We + * can calculate the color of the current pixel using that + * location. */ + if (transform > 0) { + /* Change origin to be the center of the layer. */ + xPos = xPos - dfL - dfW / 2.0; + yPos = yPos - dfT - dfH / 2.0; + + /* Flip Horizontal by reflecting across the y axis. */ + if (transform & HWC_TRANSFORM_FLIP_H) + xPos = -xPos; + + /* Flip vertical by reflecting across the x axis. */ + if (transform & HWC_TRANSFORM_FLIP_V) + yPos = -yPos; + + /* Rotate 90 by using a basic linear algebra rotation + * and scaling the result so the display frame remains + * the same. For example, a buffer of size 100x50 should + * rotate 90 degress but remain the same dimension + * (100x50) at the end of the transformation. */ + if (transform & HWC_TRANSFORM_ROT_90) { + float tmp = xPos; + xPos = -yPos * dfW / dfH; + yPos = tmp * dfH / dfW; + } + + /* Change origin back to the top left corner of the + * layer. */ + xPos = xPos + dfL + dfW / 2.0; + yPos = yPos + dfT + dfH / 2.0; + } + + hwc_frect_t sc = testLayers->getSourceCrop(*layer); + float scL = sc.left, scT = sc.top; + + float dfWDivScW = dfW / (sc.right - scL); + float dfHDivScH = dfH / (sc.bottom - scT); + + float max = 255, min = 0; + + /* Choose the pixel color. Similar to generateBuffer, + * each layer will be divided into 3x3 colors. Because + * both the source crop and display frame must be taken into + * account, the formulas are more complicated. + * + * If the source crop and display frame were not taken into + * account, we would simply divide the buffer into three + * sections by height. Each section would get one color. + * For example the formula for the first section would be: + * + * if (yPos < bufferArea.height / 3) + * //Select first section color + * + * However the pixel color is chosen based on the source + * crop and displayed based on the display frame. + * + * If the display frame top was 0 and the source crop height + * and display frame height were the same. The only factor + * would be the source crop top. To calculate the new + * section boundary, the section boundary would be moved up + * by the height of the source crop top. The formula would + * be: + * if (yPos < (bufferArea.height / 3 - sourceCrop.top) + * //Select first section color + * + * If the display frame top could also vary but source crop + * and display frame heights were the same, the formula + * would be: + * if (yPos < (bufferArea.height / 3 - sourceCrop.top + * + displayFrameTop) + * //Select first section color + * + * If the heights were not the same, the conversion between + * the source crop and display frame dimensions must be + * taken into account. The formula would be: + * if (yPos < ((bufferArea.height / 3) - sourceCrop.top) + * * displayFrameHeight / sourceCropHeight + * + displayFrameTop) + * //Select first section color + */ + if (yPos < ((bHDiv3) - scT) * dfHDivScH + dfT) { + min = 255 / 2; + } else if (yPos >= ((bH2Div3) - scT) * dfHDivScH + dfT) { + max = 255 / 2; + } + + uint8_t rCur = min, gCur = min, bCur = min; + float aCur = 1.0f; + + /* This further divides the color sections from 3 to 3x3. + * The math behind it follows the same logic as the previous + * comment */ + if (xPos < ((bWDiv3) - scL) * (dfWDivScW) + dfL) { + rCur = max; + } else if (xPos < ((bW2Div3) - scL) * (dfWDivScW) + dfL) { + gCur = max; + } else { + bCur = max; + } + + + /* Blend the pixel color with the previous layers' pixel + * colors using the plane alpha and blend mode. The final + * pixel color is chosen using the plane alpha and blend + * mode formulas found in hwcomposer2.h */ + hwc2_blend_mode_t blendMode = testLayers->getBlendMode(*layer); + + if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) { + rCur *= planeAlpha; + gCur *= planeAlpha; + bCur *= planeAlpha; + } + + aCur *= planeAlpha; + + if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) { + r = rCur + r * (1.0 - aCur); + g = gCur + g * (1.0 - aCur); + b = bCur + b * (1.0 - aCur); + a = aCur + a * (1.0 - aCur); + } else if (blendMode == HWC2_BLEND_MODE_COVERAGE) { + r = rCur * aCur + r * (1.0 - aCur); + g = gCur * aCur + g * (1.0 - aCur); + b = bCur * aCur + b * (1.0 - aCur); + a = aCur * aCur + a * (1.0 - aCur); + } else { + r = rCur; + g = gCur; + b = bCur; + a = aCur; + } + } + + /* Set the pixel color */ + setColor(x, y, mFormat, stride, img, r, g, b, a * 255); + } + } + + mGraphicBuffer->unlock(); + + *outFence = mFenceGenerator->get(); + *outHandle = mGraphicBuffer->handle; + + return 0; +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h new file mode 100644 index 0000000000..ca60940aa9 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef _HWC2_TEST_BUFFER_H +#define _HWC2_TEST_BUFFER_H + +#include <android-base/unique_fd.h> +#include <set> + +#include <hardware/hwcomposer2.h> + +#include <gui/GraphicBufferAlloc.h> +#include <ui/GraphicBuffer.h> + +#include "Hwc2TestProperties.h" + +class Hwc2TestFenceGenerator; +class Hwc2TestLayers; + +class Hwc2TestBuffer { +public: + Hwc2TestBuffer(); + ~Hwc2TestBuffer(); + + void updateBufferArea(const Area& bufferArea); + + int get(buffer_handle_t* outHandle, int32_t* outFence); + +protected: + int generateBuffer(); + + android::GraphicBufferAlloc mGraphicBufferAlloc; + android::sp<android::GraphicBuffer> mGraphicBuffer; + + std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator; + + Area mBufferArea = {-1, -1}; + const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888; + + bool mValidBuffer = false; + buffer_handle_t mHandle = nullptr; +}; + + +class Hwc2TestClientTargetBuffer { +public: + Hwc2TestClientTargetBuffer(); + ~Hwc2TestClientTargetBuffer(); + + int get(buffer_handle_t* outHandle, int32_t* outFence, + const Area& bufferArea, const Hwc2TestLayers* testLayers, + const std::set<hwc2_layer_t>* clientLayers, + const std::set<hwc2_layer_t>* clearLayers); + +protected: + android::GraphicBufferAlloc mGraphicBufferAlloc; + android::sp<android::GraphicBuffer> mGraphicBuffer; + + std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator; + + const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888; +}; + +#endif /* ifndef _HWC2_TEST_BUFFER_H */ diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp new file mode 100644 index 0000000000..69254921d4 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2016 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 <sstream> + +#include <ui/Rect.h> + +#include "Hwc2TestClientTarget.h" + +int Hwc2TestClientTarget::getBuffer(const Hwc2TestLayers& testLayers, + const std::set<hwc2_layer_t>& clientLayers, + const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget, + const Area& displayArea, buffer_handle_t* outHandle, + int32_t* outAcquireFence) +{ + if (!flipClientTarget) { + bool needsClientTarget = false; + + for (auto clientLayer : clientLayers) { + if (testLayers.getVisibleRegion(clientLayer).numRects > 0) { + needsClientTarget = true; + break; + } + } + + if (!needsClientTarget) { + *outHandle = nullptr; + *outAcquireFence = -1; + return 0; + } + } + + return mBuffer.get(outHandle, outAcquireFence, displayArea, + &testLayers, &clientLayers, &clearLayers); +} + + +Hwc2TestClientTargetSupport::Hwc2TestClientTargetSupport( + Hwc2TestCoverage coverage, const Area& displayArea) + : mBufferArea(coverage, displayArea), + mDataspace(coverage), + mSurfaceDamage(coverage) +{ + mBufferArea.setDependent(&mSurfaceDamage); +} + +std::string Hwc2TestClientTargetSupport::dump() const +{ + std::stringstream dmp; + + dmp << "client target: \n"; + + for (auto property : properties) { + dmp << property->dump(); + } + + return dmp.str(); +} + +void Hwc2TestClientTargetSupport::reset() +{ + for (auto property : properties) { + property->reset(); + } +} + +bool Hwc2TestClientTargetSupport::advance() +{ + for (auto property : properties) { + if (property->advance()) + return true; + } + return false; +} + +Area Hwc2TestClientTargetSupport::getBufferArea() const +{ + return mBufferArea.get(); +} + +android_dataspace_t Hwc2TestClientTargetSupport::getDataspace() const +{ + return mDataspace.get(); +} + +const hwc_region_t Hwc2TestClientTargetSupport::getSurfaceDamage() const +{ + return mSurfaceDamage.get(); +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h new file mode 100644 index 0000000000..3b47978bef --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef _HWC2_TEST_CLIENT_TARGET_H +#define _HWC2_TEST_CLIENT_TARGET_H + +#include <set> + +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + +#include "Hwc2TestProperties.h" +#include "Hwc2TestLayers.h" + +/* Generates client target buffers from client composition layers */ +class Hwc2TestClientTarget { +public: + int getBuffer(const Hwc2TestLayers& layers, + const std::set<hwc2_layer_t>& clientLayers, + const std::set<hwc2_layer_t>& clearLayers, + bool clearClientTarget, const Area& displayArea, + buffer_handle_t* outHandle, int32_t* outAcquireFence); + +private: + Hwc2TestClientTargetBuffer mBuffer; +}; + +/* Generates valid client targets to test which ones the device will support */ +class Hwc2TestClientTargetSupport { +public: + Hwc2TestClientTargetSupport(Hwc2TestCoverage coverage, + const Area& displayArea); + + std::string dump() const; + + void reset(); + bool advance(); + + Area getBufferArea() const; + android_dataspace_t getDataspace() const; + const hwc_region_t getSurfaceDamage() const; + +private: + std::array<Hwc2TestContainer*, 3> properties = {{ + &mDataspace, &mSurfaceDamage, &mBufferArea + }}; + + Hwc2TestBufferArea mBufferArea; + Hwc2TestDataspace mDataspace; + Hwc2TestSurfaceDamage mSurfaceDamage; +}; + +#endif /* ifndef _HWC2_TEST_CLIENT_TARGET_H */ diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp new file mode 100644 index 0000000000..937fce28fb --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2016 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 <sstream> + +#include "Hwc2TestLayer.h" + +Hwc2TestCoverage getCoverage(Hwc2TestPropertyName property, + Hwc2TestCoverage coverage, const std::unordered_map<Hwc2TestPropertyName, + Hwc2TestCoverage>& coverageExceptions) { + auto exception = coverageExceptions.find(property); + return (exception != coverageExceptions.end())? exception->second : coverage; +} + +Hwc2TestLayer::Hwc2TestLayer(Hwc2TestCoverage coverage, + const Area& displayArea) + : Hwc2TestLayer(coverage, displayArea, + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>()) { } + +Hwc2TestLayer::Hwc2TestLayer(Hwc2TestCoverage coverage, + const Area& displayArea, const std::unordered_map<Hwc2TestPropertyName, + Hwc2TestCoverage>& coverageExceptions) + : mBlendMode(getCoverage(Hwc2TestPropertyName::BlendMode, coverage, + coverageExceptions)), + mBufferArea(getCoverage(Hwc2TestPropertyName::BufferArea, coverage, + coverageExceptions), displayArea), + mColor(getCoverage(Hwc2TestPropertyName::Color, coverage, + coverageExceptions)), + mComposition(getCoverage(Hwc2TestPropertyName::Composition, coverage, + coverageExceptions)), + mDataspace(getCoverage(Hwc2TestPropertyName::Dataspace, coverage, + coverageExceptions)), + mDisplayFrame(getCoverage(Hwc2TestPropertyName::DisplayFrame, coverage, + coverageExceptions), displayArea), + mPlaneAlpha(getCoverage(Hwc2TestPropertyName::PlaneAlpha, coverage, + coverageExceptions)), + mSourceCrop(getCoverage(Hwc2TestPropertyName::SourceCrop, coverage, + coverageExceptions)), + mSurfaceDamage(getCoverage(Hwc2TestPropertyName::SurfaceDamage, coverage, + coverageExceptions)), + mTransform(getCoverage(Hwc2TestPropertyName::Transform, coverage, + coverageExceptions)) +{ + mBufferArea.setDependent(&mBuffer); + mBufferArea.setDependent(&mSourceCrop); + mBufferArea.setDependent(&mSurfaceDamage); + mBlendMode.setDependent(&mColor); +} + +std::string Hwc2TestLayer::dump() const +{ + std::stringstream dmp; + + dmp << "layer: \n"; + + for (auto property : mProperties) { + dmp << property->dump(); + } + + dmp << mVisibleRegion.dump(); + dmp << "\tz order: " << mZOrder << "\n"; + + return dmp.str(); +} + +int Hwc2TestLayer::getBuffer(buffer_handle_t* outHandle, + android::base::unique_fd* outAcquireFence) +{ + int32_t acquireFence; + int ret = mBuffer.get(outHandle, &acquireFence); + outAcquireFence->reset(acquireFence); + return ret; +} + +int Hwc2TestLayer::getBuffer(buffer_handle_t* outHandle, + int32_t* outAcquireFence) +{ + return mBuffer.get(outHandle, outAcquireFence); +} + +void Hwc2TestLayer::setZOrder(uint32_t zOrder) +{ + mZOrder = zOrder; +} + +void Hwc2TestLayer::setVisibleRegion(const android::Region& region) +{ + return mVisibleRegion.set(region); +} + +void Hwc2TestLayer::reset() +{ + mVisibleRegion.release(); + + for (auto property : mProperties) { + property->reset(); + } +} + +bool Hwc2TestLayer::advance() +{ + for (auto property : mProperties) { + if (property->isSupported(mComposition.get())) + if (property->advance()) + return true; + } + return false; +} + +hwc2_blend_mode_t Hwc2TestLayer::getBlendMode() const +{ + return mBlendMode.get(); +} + +Area Hwc2TestLayer::getBufferArea() const +{ + return mBufferArea.get(); +} + +hwc_color_t Hwc2TestLayer::getColor() const +{ + return mColor.get(); +} + +hwc2_composition_t Hwc2TestLayer::getComposition() const +{ + return mComposition.get(); +} + +/* The cursor position corresponds to {displayFrame.left, displayFrame.top} */ +hwc_rect_t Hwc2TestLayer::getCursorPosition() const +{ + return mDisplayFrame.get(); +} + +android_dataspace_t Hwc2TestLayer::getDataspace() const +{ + return mDataspace.get(); +} + +hwc_rect_t Hwc2TestLayer::getDisplayFrame() const +{ + return mDisplayFrame.get(); +} + +float Hwc2TestLayer::getPlaneAlpha() const +{ + return mPlaneAlpha.get(); +} + +hwc_frect_t Hwc2TestLayer::getSourceCrop() const +{ + return mSourceCrop.get(); +} + +hwc_region_t Hwc2TestLayer::getSurfaceDamage() const +{ + return mSurfaceDamage.get(); +} + +hwc_transform_t Hwc2TestLayer::getTransform() const +{ + return mTransform.get(); +} + +hwc_region_t Hwc2TestLayer::getVisibleRegion() const +{ + return mVisibleRegion.get(); +} + +uint32_t Hwc2TestLayer::getZOrder() const +{ + return mZOrder; +} + +bool Hwc2TestLayer::advanceBlendMode() +{ + return mBlendMode.advance(); +} + +bool Hwc2TestLayer::advanceBufferArea() +{ + return mBufferArea.advance(); +} + +bool Hwc2TestLayer::advanceColor() +{ + return mColor.advance(); +} + +bool Hwc2TestLayer::advanceComposition() +{ + return mComposition.advance(); +} + +bool Hwc2TestLayer::advanceCursorPosition() +{ + return mDisplayFrame.advance(); +} + +bool Hwc2TestLayer::advanceDataspace() +{ + return mDataspace.advance(); +} + +bool Hwc2TestLayer::advanceDisplayFrame() +{ + return mDisplayFrame.advance(); +} + +bool Hwc2TestLayer::advancePlaneAlpha() +{ + return mPlaneAlpha.advance(); +} + +bool Hwc2TestLayer::advanceSourceCrop() +{ + return mSourceCrop.advance(); +} + +bool Hwc2TestLayer::advanceSurfaceDamage() +{ + return mSurfaceDamage.advance(); +} + +bool Hwc2TestLayer::advanceTransform() +{ + return mTransform.advance(); +} + +bool Hwc2TestLayer::advanceVisibleRegion() +{ + if (mPlaneAlpha.advance()) + return true; + return mDisplayFrame.advance(); +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h new file mode 100644 index 0000000000..0e7dd228fb --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef _HWC2_TEST_LAYER_H +#define _HWC2_TEST_LAYER_H + +#include <android-base/unique_fd.h> +#include <unordered_map> + +#include "Hwc2TestBuffer.h" +#include "Hwc2TestProperties.h" + +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + +class Hwc2TestLayer { +public: + Hwc2TestLayer(Hwc2TestCoverage coverage, const Area& displayArea); + + Hwc2TestLayer(Hwc2TestCoverage coverage, const Area& displayArea, + const std::unordered_map<Hwc2TestPropertyName, + Hwc2TestCoverage>& coverage_exceptions); + + std::string dump() const; + + int getBuffer(buffer_handle_t* outHandle, + android::base::unique_fd* outAcquireFence); + int getBuffer(buffer_handle_t* outHandle, int32_t* outAcquireFence); + + void setZOrder(uint32_t zOrder); + void setVisibleRegion(const android::Region& region); + + void reset(); + bool advance(); + + hwc2_blend_mode_t getBlendMode() const; + Area getBufferArea() const; + hwc_color_t getColor() const; + hwc2_composition_t getComposition() const; + hwc_rect_t getCursorPosition() const; + android_dataspace_t getDataspace() const; + hwc_rect_t getDisplayFrame() const; + float getPlaneAlpha() const; + hwc_frect_t getSourceCrop() const; + hwc_region_t getSurfaceDamage() const; + hwc_transform_t getTransform() const; + hwc_region_t getVisibleRegion() const; + uint32_t getZOrder() const; + + bool advanceBlendMode(); + bool advanceBufferArea(); + bool advanceColor(); + bool advanceComposition(); + bool advanceCursorPosition(); + bool advanceDataspace(); + bool advanceDisplayFrame(); + bool advancePlaneAlpha(); + bool advanceSourceCrop(); + bool advanceSurfaceDamage(); + bool advanceTransform(); + bool advanceVisibleRegion(); + +private: + std::array<Hwc2TestContainer*, 10> mProperties = {{ + &mTransform, &mColor, &mDataspace, &mPlaneAlpha, &mSourceCrop, + &mSurfaceDamage, &mBlendMode, &mBufferArea, &mDisplayFrame, + &mComposition + }}; + + Hwc2TestBuffer mBuffer; + + Hwc2TestBlendMode mBlendMode; + Hwc2TestBufferArea mBufferArea; + Hwc2TestColor mColor; + Hwc2TestComposition mComposition; + Hwc2TestDataspace mDataspace; + Hwc2TestDisplayFrame mDisplayFrame; + Hwc2TestPlaneAlpha mPlaneAlpha; + Hwc2TestSourceCrop mSourceCrop; + Hwc2TestSurfaceDamage mSurfaceDamage; + Hwc2TestTransform mTransform; + Hwc2TestVisibleRegion mVisibleRegion; + + uint32_t mZOrder = UINT32_MAX; +}; + +#endif /* ifndef _HWC2_TEST_LAYER_H */ diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp new file mode 100644 index 0000000000..495ef79609 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp @@ -0,0 +1,281 @@ +/* * Copyright (C) 2016 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 <sstream> +#include <gtest/gtest.h> + +#include "Hwc2TestLayers.h" + +Hwc2TestLayers::Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers, + Hwc2TestCoverage coverage, const Area& displayArea) + : Hwc2TestLayers(layers, coverage, displayArea, + std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>()) { } + +Hwc2TestLayers::Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers, + Hwc2TestCoverage coverage, const Area& displayArea, + const std::unordered_map<Hwc2TestPropertyName, + Hwc2TestCoverage>& coverageExceptions) + : mDisplayArea(displayArea) +{ + for (auto layer : layers) { + mTestLayers.emplace(std::piecewise_construct, + std::forward_as_tuple(layer), + std::forward_as_tuple(coverage, displayArea, coverageExceptions)); + } + + /* Iterate over the layers in order and assign z orders in the same order. + * This allows us to iterate over z orders in the same way when computing + * visible regions */ + uint32_t nextZOrder = layers.size(); + + for (auto& testLayer : mTestLayers) { + testLayer.second.setZOrder(nextZOrder--); + } + + setVisibleRegions(); +} + +std::string Hwc2TestLayers::dump() const +{ + std::stringstream dmp; + for (auto& testLayer : mTestLayers) { + dmp << testLayer.second.dump(); + } + return dmp.str(); +} + +void Hwc2TestLayers::reset() +{ + for (auto& testLayer : mTestLayers) { + testLayer.second.reset(); + } + + setVisibleRegions(); +} + +bool Hwc2TestLayers::advance() +{ + auto itr = mTestLayers.begin(); + bool optimized; + + while (itr != mTestLayers.end()) { + if (itr->second.advance()) { + optimized = setVisibleRegions(); + if (!mOptimize || optimized) + return true; + itr = mTestLayers.begin(); + } else { + itr->second.reset(); + ++itr; + } + } + return false; +} + +bool Hwc2TestLayers::advanceVisibleRegions() +{ + auto itr = mTestLayers.begin(); + bool optimized; + + while (itr != mTestLayers.end()) { + if (itr->second.advanceVisibleRegion()) { + optimized = setVisibleRegions(); + if (!mOptimize || optimized) + return true; + itr = mTestLayers.begin(); + } else { + itr->second.reset(); + ++itr; + } + } + return false; +} + +/* Removes layouts that do not cover the entire display. + * Also removes layouts where a layer is completely blocked from view. + */ +bool Hwc2TestLayers::optimizeLayouts() +{ + mOptimize = true; + + if (setVisibleRegions()) + return true; + return advance(); +} + +bool Hwc2TestLayers::contains(hwc2_layer_t layer) const +{ + return mTestLayers.count(layer) != 0; +} + +int Hwc2TestLayers::getBuffer(hwc2_layer_t layer, buffer_handle_t* outHandle, + int32_t* outAcquireFence) +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getBuffer(outHandle, outAcquireFence); +} + +hwc2_blend_mode_t Hwc2TestLayers::getBlendMode(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getBlendMode(); +} + +Area Hwc2TestLayers::getBufferArea(hwc2_layer_t layer) const +{ + auto testLayer = mTestLayers.find(layer); + if (testLayer == mTestLayers.end()) + [] () { GTEST_FAIL(); }(); + return testLayer->second.getBufferArea(); +} + +hwc_color_t Hwc2TestLayers::getColor(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getColor(); +} + +hwc2_composition_t Hwc2TestLayers::getComposition(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getComposition(); +} + +hwc_rect_t Hwc2TestLayers::getCursorPosition(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getCursorPosition(); +} + +android_dataspace_t Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getDataspace(); +} + +hwc_rect_t Hwc2TestLayers::getDisplayFrame(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getDisplayFrame(); +} + +float Hwc2TestLayers::getPlaneAlpha(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getPlaneAlpha(); +} + +hwc_frect_t Hwc2TestLayers::getSourceCrop(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getSourceCrop(); +} + +hwc_region_t Hwc2TestLayers::getSurfaceDamage(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getSurfaceDamage(); +} + +hwc_transform_t Hwc2TestLayers::getTransform(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getTransform(); +} + +hwc_region_t Hwc2TestLayers::getVisibleRegion(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getVisibleRegion(); +} + +uint32_t Hwc2TestLayers::getZOrder(hwc2_layer_t layer) const +{ + if (mTestLayers.count(layer) == 0) { + []() { GTEST_FAIL(); }(); + } + return mTestLayers.at(layer).getZOrder(); +} + +/* Sets the visible regions for a display. Returns false if the layers do not + * cover the entire display or if a layer is not visible */ +bool Hwc2TestLayers::setVisibleRegions() +{ + /* The region of the display that is covered by layers above the current + * layer */ + android::Region aboveOpaqueLayers; + + bool optimized = true; + + /* Iterate over test layers from max z order to min z order. */ + for (auto& testLayer : mTestLayers) { + android::Region visibleRegion; + + /* Set the visible region of this layer */ + const hwc_rect_t displayFrame = testLayer.second.getDisplayFrame(); + + visibleRegion.set(android::Rect(displayFrame.left, displayFrame.top, + displayFrame.right, displayFrame.bottom)); + + /* Remove the area covered by opaque layers above this layer + * from this layer's visible region */ + visibleRegion.subtractSelf(aboveOpaqueLayers); + + testLayer.second.setVisibleRegion(visibleRegion); + + /* If a layer is not visible, return false */ + if (visibleRegion.isEmpty()) + optimized = false; + + /* If this layer is opaque, store the region it covers */ + if (testLayer.second.getPlaneAlpha() == 1.0f) + aboveOpaqueLayers.orSelf(visibleRegion); + } + + /* If the opaque region does not cover the entire display return false */ + if (!aboveOpaqueLayers.isRect()) + return false; + + const auto rect = aboveOpaqueLayers.begin(); + if (rect->left != 0 || rect->top != 0 || rect->right != mDisplayArea.width + || rect->bottom != mDisplayArea.height) + return false; + + return optimized; +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h new file mode 100644 index 0000000000..d95a91f485 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef _HWC2_TEST_LAYERS_H +#define _HWC2_TEST_LAYERS_H + +#include <map> + +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + +#include "Hwc2TestProperties.h" +#include "Hwc2TestLayer.h" + +class Hwc2TestLayers { +public: + Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers, + Hwc2TestCoverage coverage, const Area& displayArea); + + Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers, + Hwc2TestCoverage coverage, const Area& displayArea, + const std::unordered_map<Hwc2TestPropertyName, + Hwc2TestCoverage>& coverageExceptions); + + std::string dump() const; + + void reset(); + + bool advance(); + bool advanceVisibleRegions(); + + /* Test cases with multiple layers and property values can take quite some + * time to run. A significant amount of time can be spent on test cases + * where one layer is changing property values but is not visible. To + * decrease runtime, this function can be called. Removes layouts where a + * layer is completely blocked from view. It also removes layouts that do + * not cover the entire display.*/ + bool optimizeLayouts(); + + bool contains(hwc2_layer_t layer) const; + + int getBuffer(hwc2_layer_t layer, buffer_handle_t* outHandle, + int32_t* outAcquireFence); + + hwc2_blend_mode_t getBlendMode(hwc2_layer_t layer) const; + Area getBufferArea(hwc2_layer_t layer) const; + hwc_color_t getColor(hwc2_layer_t layer) const; + hwc2_composition_t getComposition(hwc2_layer_t layer) const; + hwc_rect_t getCursorPosition(hwc2_layer_t layer) const; + android_dataspace_t getDataspace(hwc2_layer_t layer) const; + hwc_rect_t getDisplayFrame(hwc2_layer_t layer) const; + android_pixel_format_t getFormat(hwc2_layer_t layer) const; + float getPlaneAlpha(hwc2_layer_t layer) const; + hwc_frect_t getSourceCrop(hwc2_layer_t layer) const; + hwc_region_t getSurfaceDamage(hwc2_layer_t layer) const; + hwc_transform_t getTransform(hwc2_layer_t layer) const; + hwc_region_t getVisibleRegion(hwc2_layer_t layer) const; + uint32_t getZOrder(hwc2_layer_t layer) const; + +private: + bool setVisibleRegions(); + + std::map<hwc2_layer_t, Hwc2TestLayer> mTestLayers; + + Area mDisplayArea; + + bool mOptimize = false; +}; + +#endif /* ifndef _HWC2_TEST_LAYERS_H */ diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp new file mode 100644 index 0000000000..b5522de3a5 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp @@ -0,0 +1,782 @@ +/* + * Copyright (C) 2016 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 <sstream> +#include <cutils/log.h> +#include <ui/Rect.h> + +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + +#include "Hwc2TestBuffer.h" +#include "Hwc2TestProperties.h" + +Hwc2TestBufferArea::Hwc2TestBufferArea(Hwc2TestCoverage coverage, + const Area& displayArea) + : Hwc2TestProperty(mBufferAreas, mCompositionSupport), + mScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteScalars: + (coverage == Hwc2TestCoverage::Basic)? mBasicScalars: + mDefaultScalars), + mDisplayArea(displayArea) +{ + update(); +} + +std::string Hwc2TestBufferArea::dump() const +{ + std::stringstream dmp; + const Area& curr = get(); + dmp << "\tbuffer area: width " << curr.width << ", height " << curr.height + << "\n"; + return dmp.str(); +} + +void Hwc2TestBufferArea::setDependent(Hwc2TestBuffer* buffer) +{ + mBuffer = buffer; + if (buffer) { + buffer->updateBufferArea(get()); + } +} + +void Hwc2TestBufferArea::setDependent(Hwc2TestSourceCrop* sourceCrop) +{ + mSourceCrop = sourceCrop; + if (mSourceCrop) { + mSourceCrop->updateBufferArea(get()); + } +} + +void Hwc2TestBufferArea::setDependent(Hwc2TestSurfaceDamage* surfaceDamage) +{ + mSurfaceDamage = surfaceDamage; + if (mSurfaceDamage) { + mSurfaceDamage->updateBufferArea(get()); + } +} + +void Hwc2TestBufferArea::update() +{ + mBufferAreas.clear(); + + if (mDisplayArea.width == 0 && mDisplayArea.height == 0) { + mBufferAreas.push_back({0, 0}); + return; + } + + for (auto scalar : mScalars) { + mBufferAreas.push_back({static_cast<int32_t>(scalar * mDisplayArea.width), + static_cast<int32_t>(scalar * mDisplayArea.height)}); + } + + updateDependents(); +} + +void Hwc2TestBufferArea::updateDependents() +{ + const Area& curr = get(); + + if (mBuffer) + mBuffer->updateBufferArea(curr); + if (mSourceCrop) + mSourceCrop->updateBufferArea(curr); + if (mSurfaceDamage) + mSurfaceDamage->updateBufferArea(curr); +} + +const std::vector<float> Hwc2TestBufferArea::mDefaultScalars = { + 1.0f, +}; + +const std::vector<float> Hwc2TestBufferArea::mBasicScalars = { + 1.0f, 0.5f, +}; + +const std::vector<float> Hwc2TestBufferArea::mCompleteScalars = { + 1.0f, 0.75f, 0.5f +}; + + +Hwc2TestBlendMode::Hwc2TestBlendMode(Hwc2TestCoverage coverage) + : Hwc2TestProperty(coverage, mCompleteBlendModes, mBasicBlendModes, + mDefaultBlendModes, mCompositionSupport) { } + +std::string Hwc2TestBlendMode::dump() const +{ + std::stringstream dmp; + dmp << "\tblend mode: " << getBlendModeName(get()) << "\n"; + return dmp.str(); +} + +void Hwc2TestBlendMode::setDependent(Hwc2TestColor* color) +{ + mColor = color; + updateDependents(); +} + +void Hwc2TestBlendMode::updateDependents() +{ + if (mColor) + mColor->updateBlendMode(get()); +} + +const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mDefaultBlendModes = { + HWC2_BLEND_MODE_NONE, +}; + +const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mBasicBlendModes = { + HWC2_BLEND_MODE_NONE, + HWC2_BLEND_MODE_PREMULTIPLIED, +}; + +const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mCompleteBlendModes = { + HWC2_BLEND_MODE_NONE, + HWC2_BLEND_MODE_PREMULTIPLIED, + HWC2_BLEND_MODE_COVERAGE, +}; + + +Hwc2TestColor::Hwc2TestColor(Hwc2TestCoverage coverage, + hwc2_blend_mode_t blendMode) + : Hwc2TestProperty(mColors, mCompositionSupport), + mBaseColors((coverage == Hwc2TestCoverage::Complete)? mCompleteBaseColors: + (coverage == Hwc2TestCoverage::Basic)? mBasicBaseColors: + mDefaultBaseColors), + mBlendMode(blendMode) +{ + update(); +} + +std::string Hwc2TestColor::dump() const +{ + std::stringstream dmp; + const hwc_color_t& color = get(); + dmp << "\tcolor: r " << std::to_string(color.r) << ", g " + << std::to_string(color.g) << ", b " << std::to_string(color.b) + << ", a " << std::to_string(color.a) << "\n"; + return dmp.str(); +} + +void Hwc2TestColor::updateBlendMode(hwc2_blend_mode_t blendMode) +{ + mBlendMode = blendMode; + update(); +} + +void Hwc2TestColor::update() +{ + if (mBlendMode != HWC2_BLEND_MODE_PREMULTIPLIED) { + mColors = mBaseColors; + return; + } + + mColors.clear(); + + for (const hwc_color_t& baseColor : mBaseColors) { + if (baseColor.a >= baseColor.r && baseColor.a >= baseColor.g + && baseColor.a >= baseColor.b) { + mColors.push_back(baseColor); + } + } + +} + +const std::vector<hwc_color_t> Hwc2TestColor::mDefaultBaseColors = { + {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX}, +}; + +const std::vector<hwc_color_t> Hwc2TestColor::mBasicBaseColors = { + {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX}, + { 0, 0, 0, 0}, +}; + +const std::vector<hwc_color_t> Hwc2TestColor::mCompleteBaseColors = { + {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX}, + {UINT8_MAX, UINT8_MAX, UINT8_MAX, 0}, + {UINT8_MAX, UINT8_MAX, 0, UINT8_MAX}, + {UINT8_MAX, UINT8_MAX, 0, 0}, + {UINT8_MAX, 0, UINT8_MAX, UINT8_MAX}, + {UINT8_MAX, 0, UINT8_MAX, 0}, + {UINT8_MAX, 0, 0, UINT8_MAX}, + {UINT8_MAX, 0, 0, 0}, + { 0, UINT8_MAX, UINT8_MAX, UINT8_MAX}, + { 0, UINT8_MAX, UINT8_MAX, 0}, + { 0, UINT8_MAX, 0, UINT8_MAX}, + { 0, UINT8_MAX, 0, 0}, + { 0, 0, UINT8_MAX, UINT8_MAX}, + { 0, 0, UINT8_MAX, 0}, + { 0, 0, 0, UINT8_MAX}, + { 0, 0, 0, 0}, +}; + + +Hwc2TestComposition::Hwc2TestComposition(Hwc2TestCoverage coverage) + : Hwc2TestProperty(coverage, mCompleteCompositions, mBasicCompositions, + mDefaultCompositions, mCompositionSupport) { } + +std::string Hwc2TestComposition::dump() const +{ + std::stringstream dmp; + dmp << "\tcomposition: " << getCompositionName(get()) << "\n"; + return dmp.str(); +} + +const std::vector<hwc2_composition_t> Hwc2TestComposition::mDefaultCompositions = { + HWC2_COMPOSITION_DEVICE, +}; + +const std::vector<hwc2_composition_t> Hwc2TestComposition::mBasicCompositions = { + HWC2_COMPOSITION_CLIENT, + HWC2_COMPOSITION_DEVICE, +}; + +const std::vector<hwc2_composition_t> Hwc2TestComposition::mCompleteCompositions = { + HWC2_COMPOSITION_CLIENT, + HWC2_COMPOSITION_DEVICE, + HWC2_COMPOSITION_SOLID_COLOR, + HWC2_COMPOSITION_CURSOR, + HWC2_COMPOSITION_SIDEBAND, +}; + + +Hwc2TestDataspace::Hwc2TestDataspace(Hwc2TestCoverage coverage) + : Hwc2TestProperty(coverage, completeDataspaces, basicDataspaces, + defaultDataspaces, mCompositionSupport) { } + +std::string Hwc2TestDataspace::dump() const +{ + std::stringstream dmp; + dmp << "\tdataspace: " << get() << "\n"; + return dmp.str(); +} + +const std::vector<android_dataspace_t> Hwc2TestDataspace::defaultDataspaces = { + HAL_DATASPACE_UNKNOWN, +}; + +const std::vector<android_dataspace_t> Hwc2TestDataspace::basicDataspaces = { + HAL_DATASPACE_UNKNOWN, + HAL_DATASPACE_V0_SRGB, +}; + +const std::vector<android_dataspace_t> Hwc2TestDataspace::completeDataspaces = { + HAL_DATASPACE_UNKNOWN, + HAL_DATASPACE_ARBITRARY, + HAL_DATASPACE_STANDARD_SHIFT, + HAL_DATASPACE_STANDARD_MASK, + HAL_DATASPACE_STANDARD_UNSPECIFIED, + HAL_DATASPACE_STANDARD_BT709, + HAL_DATASPACE_STANDARD_BT601_625, + HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED, + HAL_DATASPACE_STANDARD_BT601_525, + HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED, + HAL_DATASPACE_STANDARD_BT2020, + HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE, + HAL_DATASPACE_STANDARD_BT470M, + HAL_DATASPACE_STANDARD_FILM, + HAL_DATASPACE_TRANSFER_SHIFT, + HAL_DATASPACE_TRANSFER_MASK, + HAL_DATASPACE_TRANSFER_UNSPECIFIED, + HAL_DATASPACE_TRANSFER_LINEAR, + HAL_DATASPACE_TRANSFER_SRGB, + HAL_DATASPACE_TRANSFER_SMPTE_170M, + HAL_DATASPACE_TRANSFER_GAMMA2_2, + HAL_DATASPACE_TRANSFER_GAMMA2_8, + HAL_DATASPACE_TRANSFER_ST2084, + HAL_DATASPACE_TRANSFER_HLG, + HAL_DATASPACE_RANGE_SHIFT, + HAL_DATASPACE_RANGE_MASK, + HAL_DATASPACE_RANGE_UNSPECIFIED, + HAL_DATASPACE_RANGE_FULL, + HAL_DATASPACE_RANGE_LIMITED, + HAL_DATASPACE_SRGB_LINEAR, + HAL_DATASPACE_V0_SRGB_LINEAR, + HAL_DATASPACE_SRGB, + HAL_DATASPACE_V0_SRGB, + HAL_DATASPACE_JFIF, + HAL_DATASPACE_V0_JFIF, + HAL_DATASPACE_BT601_625, + HAL_DATASPACE_V0_BT601_625, + HAL_DATASPACE_BT601_525, + HAL_DATASPACE_V0_BT601_525, + HAL_DATASPACE_BT709, + HAL_DATASPACE_V0_BT709, + HAL_DATASPACE_DEPTH, +}; + + +Hwc2TestDisplayDimension::Hwc2TestDisplayDimension(Hwc2TestCoverage coverage) + : Hwc2TestProperty( + (coverage == Hwc2TestCoverage::Complete)? mCompleteDisplayDimensions: + (coverage == Hwc2TestCoverage::Basic)? mBasicDisplayDimensions: + mDefaultDisplayDimensions, mCompositionSupport) { } + +std::string Hwc2TestDisplayDimension::dump() const +{ + std::stringstream dmp; + const UnsignedArea& curr = get(); + dmp << "\tdisplay dimension: " << curr.width<< " x " << curr.height<< "\n"; + return dmp.str(); +} + +void Hwc2TestDisplayDimension::setDependent(Hwc2TestBuffer* buffer) +{ + mBuffer = buffer; + updateDependents(); +} + +void Hwc2TestDisplayDimension::updateDependents() +{ + const UnsignedArea& curr = get(); + + if (mBuffer) + mBuffer->updateBufferArea({static_cast<int32_t>(curr.width), + static_cast<int32_t>(curr.height)}); +} + +const std::vector<UnsignedArea> + Hwc2TestDisplayDimension::mDefaultDisplayDimensions = { + {1920, 1080}, +}; + +const std::vector<UnsignedArea> + Hwc2TestDisplayDimension::mBasicDisplayDimensions = { + {640, 480}, + {1280, 720}, + {1920, 1080}, + {1920, 1200}, +}; + +const std::vector<UnsignedArea> + Hwc2TestDisplayDimension::mCompleteDisplayDimensions = { + {320, 240}, + {480, 320}, + {640, 480}, + {1280, 720}, + {1920, 1080}, + {1920, 1200}, + {2560, 1440}, + {2560, 1600}, + {3840, 2160}, + {4096, 2160}, +}; + + +Hwc2TestDisplayFrame::Hwc2TestDisplayFrame(Hwc2TestCoverage coverage, + const Area& displayArea) + : Hwc2TestProperty(mDisplayFrames, mCompositionSupport), + mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars: + (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars: + mDefaultFrectScalars), + mDisplayArea(displayArea) +{ + update(); +} + +std::string Hwc2TestDisplayFrame::dump() const +{ + std::stringstream dmp; + const hwc_rect_t& displayFrame = get(); + dmp << "\tdisplay frame: left " << displayFrame.left << ", top " + << displayFrame.top << ", right " << displayFrame.right + << ", bottom " << displayFrame.bottom << "\n"; + return dmp.str(); +} + +void Hwc2TestDisplayFrame::update() +{ + mDisplayFrames.clear(); + + if (mDisplayArea.width == 0 && mDisplayArea.height == 0) { + mDisplayFrames.push_back({0, 0, 0, 0}); + return; + } + + for (const auto& frectScalar : mFrectScalars) { + mDisplayFrames.push_back({ + static_cast<int>(frectScalar.left * mDisplayArea.width), + static_cast<int>(frectScalar.top * mDisplayArea.height), + static_cast<int>(frectScalar.right * mDisplayArea.width), + static_cast<int>(frectScalar.bottom * mDisplayArea.height)}); + } +} + +const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mDefaultFrectScalars = { + {0.0, 0.0, 1.0, 1.0}, +}; + +const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mBasicFrectScalars = { + {0.0, 0.0, 1.0, 1.0}, + {0.0, 0.0, 1.0, 0.05}, + {0.0, 0.95, 1.0, 1.0}, +}; + +const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mCompleteFrectScalars = { + {0.0, 0.0, 1.0, 1.0}, + {0.0, 0.05, 1.0, 0.95}, + {0.0, 0.05, 1.0, 1.0}, + {0.0, 0.0, 1.0, 0.05}, + {0.0, 0.95, 1.0, 1.0}, + {0.25, 0.0, 0.75, 0.35}, + {0.25, 0.25, 0.75, 0.75}, +}; + + +Hwc2TestPlaneAlpha::Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage) + : Hwc2TestProperty(coverage, mCompletePlaneAlphas, mBasicPlaneAlphas, + mDefaultPlaneAlphas, mCompositionSupport) { } + +std::string Hwc2TestPlaneAlpha::dump() const +{ + std::stringstream dmp; + dmp << "\tplane alpha: " << get() << "\n"; + return dmp.str(); +} + +const std::vector<float> Hwc2TestPlaneAlpha::mDefaultPlaneAlphas = { + 1.0f, +}; + +const std::vector<float> Hwc2TestPlaneAlpha::mBasicPlaneAlphas = { + 1.0f, 0.0f, +}; + +const std::vector<float> Hwc2TestPlaneAlpha::mCompletePlaneAlphas = { + 1.0f, 0.75f, 0.5f, 0.25f, 0.0f, +}; + + +Hwc2TestSourceCrop::Hwc2TestSourceCrop(Hwc2TestCoverage coverage, + const Area& bufferArea) + : Hwc2TestProperty(mSourceCrops, mCompositionSupport), + mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars: + (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars: + mDefaultFrectScalars), + mBufferArea(bufferArea) +{ + update(); +} + +std::string Hwc2TestSourceCrop::dump() const +{ + std::stringstream dmp; + const hwc_frect_t& sourceCrop = get(); + dmp << "\tsource crop: left " << sourceCrop.left << ", top " + << sourceCrop.top << ", right " << sourceCrop.right << ", bottom " + << sourceCrop.bottom << "\n"; + return dmp.str(); +} + +void Hwc2TestSourceCrop::updateBufferArea(const Area& bufferArea) +{ + mBufferArea = bufferArea; + update(); +} + +void Hwc2TestSourceCrop::update() +{ + mSourceCrops.clear(); + + if (mBufferArea.width == 0 && mBufferArea.height == 0) { + mSourceCrops.push_back({0, 0, 0, 0}); + return; + } + + for (const auto& frectScalar : mFrectScalars) { + mSourceCrops.push_back({ + frectScalar.left * mBufferArea.width, + frectScalar.top * mBufferArea.height, + frectScalar.right * mBufferArea.width, + frectScalar.bottom * mBufferArea.height}); + } +} + +const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mDefaultFrectScalars = { + {0.0, 0.0, 1.0, 1.0}, +}; + +const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mBasicFrectScalars = { + {0.0, 0.0, 1.0, 1.0}, + {0.0, 0.0, 0.5, 0.5}, + {0.5, 0.5, 1.0, 1.0}, +}; + +const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mCompleteFrectScalars = { + {0.0, 0.0, 1.0, 1.0}, + {0.0, 0.0, 0.5, 0.5}, + {0.5, 0.5, 1.0, 1.0}, + {0.0, 0.0, 0.25, 0.25}, + {0.25, 0.25, 0.75, 0.75}, +}; + + +Hwc2TestSurfaceDamage::Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage) + : Hwc2TestProperty(mSurfaceDamages, mCompositionSupport), + mRegionScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteRegionScalars: + (coverage == Hwc2TestCoverage::Basic)? mBasicRegionScalars: + mDefaultRegionScalars) +{ + update(); +} + +Hwc2TestSurfaceDamage::~Hwc2TestSurfaceDamage() +{ + freeSurfaceDamages(); +} + +std::string Hwc2TestSurfaceDamage::dump() const +{ + std::stringstream dmp; + + const hwc_region_t& curr = get(); + dmp << "\tsurface damage: region count " << curr.numRects << "\n"; + for (size_t i = 0; i < curr.numRects; i++) { + const hwc_rect_t& rect = curr.rects[i]; + dmp << "\t\trect: left " << rect.left << ", top " << rect.top + << ", right " << rect.right << ", bottom " << rect.bottom << "\n"; + } + + return dmp.str(); +} + +void Hwc2TestSurfaceDamage::updateBufferArea(const Area& bufferArea) +{ + mBufferArea = bufferArea; + update(); +} + +void Hwc2TestSurfaceDamage::update() +{ + freeSurfaceDamages(); + + if (mBufferArea.width == 0 && mBufferArea.height == 0) { + mSurfaceDamages.push_back({0, nullptr}); + return; + } + + hwc_region_t damage; + + for (const auto& regionScalar : mRegionScalars) { + damage.numRects = regionScalar.size(); + + if (damage.numRects > 0) { + hwc_rect_t* rects = new hwc_rect_t[damage.numRects]; + if (!rects) { + ALOGW("failed to allocate new hwc_rect_t array"); + continue; + } + + for (size_t i = 0; i < damage.numRects; i++) { + rects[i].left = regionScalar[i].left * mBufferArea.width; + rects[i].top = regionScalar[i].top * mBufferArea.height; + rects[i].right = regionScalar[i].right * mBufferArea.width; + rects[i].bottom = regionScalar[i].bottom * mBufferArea.height; + } + + damage.rects = static_cast<hwc_rect_t const*>(rects); + } else { + damage.rects = nullptr; + } + + mSurfaceDamages.push_back(damage); + } +} + +void Hwc2TestSurfaceDamage::freeSurfaceDamages() +{ + for (const auto& surfaceDamage : mSurfaceDamages) { + if (surfaceDamage.numRects > 0 && surfaceDamage.rects) + delete[] surfaceDamage.rects; + } + mSurfaceDamages.clear(); +} + +const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mDefaultRegionScalars = { + {{}}, +}; + +const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mBasicRegionScalars = { + {{}}, + {{0.0, 0.0, 1.0, 1.0}}, +}; + +const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mCompleteRegionScalars = { + {{}}, + {{0.0, 0.0, 1.0, 1.0}}, + {{0.0, 0.0, 0.5, 0.5}, {0.5, 0.5, 1.0, 1.0}}, +}; + + +Hwc2TestTransform::Hwc2TestTransform(Hwc2TestCoverage coverage) + : Hwc2TestProperty(coverage, mCompleteTransforms, mBasicTransforms, + mDefaultTransforms, mCompositionSupport) { } + +std::string Hwc2TestTransform::dump() const +{ + std::stringstream dmp; + dmp << "\ttransform: " << getTransformName(get()) << "\n"; + return dmp.str(); +} + +const std::vector<hwc_transform_t> Hwc2TestTransform::mDefaultTransforms = { + static_cast<hwc_transform_t>(0), +}; + +const std::vector<hwc_transform_t> Hwc2TestTransform::mBasicTransforms = { + static_cast<hwc_transform_t>(0), + HWC_TRANSFORM_FLIP_H, + HWC_TRANSFORM_FLIP_V, + HWC_TRANSFORM_ROT_90, +}; + +const std::vector<hwc_transform_t> Hwc2TestTransform::mCompleteTransforms = { + static_cast<hwc_transform_t>(0), + HWC_TRANSFORM_FLIP_H, + HWC_TRANSFORM_FLIP_V, + HWC_TRANSFORM_ROT_90, + HWC_TRANSFORM_ROT_180, + HWC_TRANSFORM_ROT_270, + HWC_TRANSFORM_FLIP_H_ROT_90, + HWC_TRANSFORM_FLIP_V_ROT_90, +}; + + +Hwc2TestVisibleRegion::~Hwc2TestVisibleRegion() +{ + release(); +} + +std::string Hwc2TestVisibleRegion::dump() const +{ + std::stringstream dmp; + + const hwc_region_t& curr = get(); + dmp << "\tvisible region: region count " << curr.numRects << "\n"; + for (size_t i = 0; i < curr.numRects; i++) { + const hwc_rect_t& rect = curr.rects[i]; + dmp << "\t\trect: left " << rect.left << ", top " << rect.top + << ", right " << rect.right << ", bottom " << rect.bottom << "\n"; + } + + return dmp.str(); +} + +void Hwc2TestVisibleRegion::set(const android::Region& visibleRegion) +{ + release(); + + size_t size = 0; + const android::Rect* rects = visibleRegion.getArray(&size); + + mVisibleRegion.numRects = size; + mVisibleRegion.rects = nullptr; + + if (size > 0) { + hwc_rect_t* hwcRects = new hwc_rect_t[size]; + for (size_t i = 0; i < size; i++) { + hwcRects[i].left = rects[i].left; + hwcRects[i].top = rects[i].top; + hwcRects[i].right = rects[i].right; + hwcRects[i].bottom = rects[i].bottom; + } + mVisibleRegion.rects = hwcRects; + } +} + +hwc_region_t Hwc2TestVisibleRegion::get() const +{ + return mVisibleRegion; +} + +void Hwc2TestVisibleRegion::release() +{ + if (mVisibleRegion.numRects > 0 && mVisibleRegion.rects) + delete[] mVisibleRegion.rects; + mVisibleRegion.rects = nullptr; + mVisibleRegion.numRects = 0; +} + +/* Identifies which layer properties are supported by each composition type. + * hwc2_composition_t values range from: + * HWC2_COMPOSITION_INVALID = 0, + * HWC2_COMPOSITION_CLIENT = 1, + * HWC2_COMPOSITION_DEVICE = 2, + * HWC2_COMPOSITION_SOLID_COLOR = 3, + * HWC2_COMPOSITION_CURSOR = 4, + * HWC2_COMPOSITION_SIDEBAND = 5, + * + * Each property array can be indexed by a hwc2_composition_t value. + * By using an array instead of a more complex data structure, runtimes for + * some test cases showed a noticeable improvement. + */ + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestBufferArea::mCompositionSupport = {{ + false, true, true, false, true, true, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestBlendMode::mCompositionSupport = {{ + false, true, true, false, true, true, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestColor::mCompositionSupport = {{ + false, false, false, true, false, false, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestComposition::mCompositionSupport = {{ + false, true, true, true, true, true, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestDataspace::mCompositionSupport = {{ + false, true, true, true, true, false, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestDisplayDimension::mCompositionSupport = {{ + false, true, true, true, true, true, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestDisplayFrame::mCompositionSupport = {{ + false, true, true, true, false, true, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestPlaneAlpha::mCompositionSupport = {{ + false, true, true, true, true, true, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestSourceCrop::mCompositionSupport = {{ + false, true, true, false, true, false, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestSurfaceDamage::mCompositionSupport = {{ + false, false, true, false, true, false, +}}; + +/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */ +const std::array<bool, 6> Hwc2TestTransform::mCompositionSupport = {{ + false, true, true, false, true, true, +}}; diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h new file mode 100644 index 0000000000..c2029aba04 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef _HWC2_TEST_PROPERTIES_H +#define _HWC2_TEST_PROPERTIES_H + +#include <array> +#include <vector> + +#include <ui/Region.h> + +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + +enum class Hwc2TestCoverage { + Default = 0, + Basic, + Complete, +}; + +enum class Hwc2TestPropertyName { + BlendMode = 1, + BufferArea, + Color, + Composition, + CursorPosition, + Dataspace, + DisplayFrame, + PlaneAlpha, + SourceCrop, + SurfaceDamage, + Transform, +}; + +typedef struct { + int32_t width; + int32_t height; +} Area; + + +typedef struct { + uint32_t width; + uint32_t height; +} UnsignedArea; + + +class Hwc2TestContainer { +public: + virtual ~Hwc2TestContainer() = default; + + /* Resets the container */ + virtual void reset() = 0; + + /* Attempts to advance to the next valid value. Returns true if one can be + * found */ + virtual bool advance() = 0; + + virtual std::string dump() const = 0; + + /* Returns true if the container supports the given composition type */ + virtual bool isSupported(hwc2_composition_t composition) = 0; +}; + + +template <class T> +class Hwc2TestProperty : public Hwc2TestContainer { +public: + Hwc2TestProperty(Hwc2TestCoverage coverage, + const std::vector<T>& completeList, const std::vector<T>& basicList, + const std::vector<T>& defaultList, + const std::array<bool, 6>& compositionSupport) + : Hwc2TestProperty((coverage == Hwc2TestCoverage::Complete)? completeList: + (coverage == Hwc2TestCoverage::Basic)? basicList : defaultList, + compositionSupport) { } + + Hwc2TestProperty(const std::vector<T>& list, + const std::array<bool, 6>& compositionSupport) + : mList(list), + mCompositionSupport(compositionSupport) { } + + void reset() override + { + mListIdx = 0; + } + + bool advance() override + { + if (mListIdx + 1 < mList.size()) { + mListIdx++; + updateDependents(); + return true; + } + reset(); + updateDependents(); + return false; + } + + T get() const + { + return mList.at(mListIdx); + } + + virtual bool isSupported(hwc2_composition_t composition) + { + return mCompositionSupport.at(composition); + } + +protected: + /* If a derived class has dependents, override this function */ + virtual void updateDependents() { } + + const std::vector<T>& mList; + size_t mListIdx = 0; + + const std::array<bool, 6>& mCompositionSupport; +}; + +class Hwc2TestBuffer; +class Hwc2TestSourceCrop; +class Hwc2TestSurfaceDamage; + +class Hwc2TestBufferArea : public Hwc2TestProperty<Area> { +public: + Hwc2TestBufferArea(Hwc2TestCoverage coverage, const Area& displayArea); + + std::string dump() const override; + + void setDependent(Hwc2TestBuffer* buffer); + void setDependent(Hwc2TestSourceCrop* sourceCrop); + void setDependent(Hwc2TestSurfaceDamage* surfaceDamage); + +protected: + void update(); + void updateDependents() override; + + const std::vector<float>& mScalars; + static const std::vector<float> mDefaultScalars; + static const std::vector<float> mBasicScalars; + static const std::vector<float> mCompleteScalars; + + Area mDisplayArea; + + Hwc2TestBuffer* mBuffer = nullptr; + Hwc2TestSourceCrop* mSourceCrop = nullptr; + Hwc2TestSurfaceDamage* mSurfaceDamage = nullptr; + + std::vector<Area> mBufferAreas; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestColor; + +class Hwc2TestBlendMode : public Hwc2TestProperty<hwc2_blend_mode_t> { +public: + Hwc2TestBlendMode(Hwc2TestCoverage coverage); + + std::string dump() const override; + + void setDependent(Hwc2TestColor* color); + +protected: + void updateDependents() override; + + Hwc2TestColor* mColor = nullptr; + + static const std::vector<hwc2_blend_mode_t> mDefaultBlendModes; + static const std::vector<hwc2_blend_mode_t> mBasicBlendModes; + static const std::vector<hwc2_blend_mode_t> mCompleteBlendModes; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestColor : public Hwc2TestProperty<hwc_color_t> { +public: + Hwc2TestColor(Hwc2TestCoverage coverage, + hwc2_blend_mode_t blendMode = HWC2_BLEND_MODE_NONE); + + std::string dump() const override; + + void updateBlendMode(hwc2_blend_mode_t blendMode); + +protected: + void update(); + + std::vector<hwc_color_t> mBaseColors; + static const std::vector<hwc_color_t> mDefaultBaseColors; + static const std::vector<hwc_color_t> mBasicBaseColors; + static const std::vector<hwc_color_t> mCompleteBaseColors; + + hwc2_blend_mode_t mBlendMode; + + std::vector<hwc_color_t> mColors; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestComposition : public Hwc2TestProperty<hwc2_composition_t> { +public: + Hwc2TestComposition(Hwc2TestCoverage coverage); + + std::string dump() const override; + +protected: + static const std::vector<hwc2_composition_t> mDefaultCompositions; + static const std::vector<hwc2_composition_t> mBasicCompositions; + static const std::vector<hwc2_composition_t> mCompleteCompositions; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestDataspace : public Hwc2TestProperty<android_dataspace_t> { +public: + Hwc2TestDataspace(Hwc2TestCoverage coverage); + + std::string dump() const override; + +protected: + static const std::vector<android_dataspace_t> defaultDataspaces; + static const std::vector<android_dataspace_t> basicDataspaces; + static const std::vector<android_dataspace_t> completeDataspaces; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> { +public: + Hwc2TestDisplayDimension(Hwc2TestCoverage coverage); + + std::string dump() const; + + void setDependent(Hwc2TestBuffer* buffer); + +private: + void updateDependents(); + + Hwc2TestBuffer* mBuffer; + + static const std::vector<UnsignedArea> mDefaultDisplayDimensions; + static const std::vector<UnsignedArea> mBasicDisplayDimensions; + static const std::vector<UnsignedArea> mCompleteDisplayDimensions; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestDisplayFrame : public Hwc2TestProperty<hwc_rect_t> { +public: + Hwc2TestDisplayFrame(Hwc2TestCoverage coverage, const Area& displayArea); + + std::string dump() const override; + +protected: + void update(); + + const std::vector<hwc_frect_t>& mFrectScalars; + const static std::vector<hwc_frect_t> mDefaultFrectScalars; + const static std::vector<hwc_frect_t> mBasicFrectScalars; + const static std::vector<hwc_frect_t> mCompleteFrectScalars; + + Area mDisplayArea; + + std::vector<hwc_rect_t> mDisplayFrames; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestPlaneAlpha : public Hwc2TestProperty<float> { +public: + Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage); + + std::string dump() const override; + +protected: + static const std::vector<float> mDefaultPlaneAlphas; + static const std::vector<float> mBasicPlaneAlphas; + static const std::vector<float> mCompletePlaneAlphas; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestSourceCrop : public Hwc2TestProperty<hwc_frect_t> { +public: + Hwc2TestSourceCrop(Hwc2TestCoverage coverage, const Area& bufferArea = {0, 0}); + + std::string dump() const override; + + void updateBufferArea(const Area& bufferArea); + +protected: + void update(); + + const std::vector<hwc_frect_t>& mFrectScalars; + const static std::vector<hwc_frect_t> mDefaultFrectScalars; + const static std::vector<hwc_frect_t> mBasicFrectScalars; + const static std::vector<hwc_frect_t> mCompleteFrectScalars; + + Area mBufferArea; + + std::vector<hwc_frect_t> mSourceCrops; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestSurfaceDamage : public Hwc2TestProperty<hwc_region_t> { +public: + Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage); + ~Hwc2TestSurfaceDamage(); + + std::string dump() const override; + + void updateBufferArea(const Area& bufferArea); + +protected: + void update(); + void freeSurfaceDamages(); + + const std::vector<std::vector<hwc_frect_t>> &mRegionScalars; + const static std::vector<std::vector<hwc_frect_t>> mDefaultRegionScalars; + const static std::vector<std::vector<hwc_frect_t>> mBasicRegionScalars; + const static std::vector<std::vector<hwc_frect_t>> mCompleteRegionScalars; + + Area mBufferArea = {0, 0}; + + std::vector<hwc_region_t> mSurfaceDamages; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestTransform : public Hwc2TestProperty<hwc_transform_t> { +public: + Hwc2TestTransform(Hwc2TestCoverage coverage); + + std::string dump() const override; + +protected: + static const std::vector<hwc_transform_t> mDefaultTransforms; + static const std::vector<hwc_transform_t> mBasicTransforms; + static const std::vector<hwc_transform_t> mCompleteTransforms; + + static const std::array<bool, 6> mCompositionSupport; +}; + + +class Hwc2TestVisibleRegion { +public: + ~Hwc2TestVisibleRegion(); + + std::string dump() const; + + void set(const android::Region& visibleRegion); + hwc_region_t get() const; + void release(); + +protected: + hwc_region_t mVisibleRegion = {0, nullptr}; +}; + +#endif /* ifndef _HWC2_TEST_PROPERTIES_H */ diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp new file mode 100644 index 0000000000..d0fbc0b5ad --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 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 <sstream> + +#include "Hwc2TestVirtualDisplay.h" + +Hwc2TestVirtualDisplay::Hwc2TestVirtualDisplay( + Hwc2TestCoverage coverage) + : mDisplayDimension(coverage) +{ + mDisplayDimension.setDependent(&mBuffer); +} + +std::string Hwc2TestVirtualDisplay::dump() const +{ + std::stringstream dmp; + + dmp << "virtual display: \n"; + + mDisplayDimension.dump(); + + return dmp.str(); +} + +int Hwc2TestVirtualDisplay::getBuffer(buffer_handle_t* outHandle, + android::base::unique_fd* outAcquireFence) +{ + int32_t acquireFence; + int ret = mBuffer.get(outHandle, &acquireFence); + outAcquireFence->reset(acquireFence); + return ret; +} + +void Hwc2TestVirtualDisplay::reset() +{ + return mDisplayDimension.reset(); +} + +bool Hwc2TestVirtualDisplay::advance() +{ + return mDisplayDimension.advance(); +} + +UnsignedArea Hwc2TestVirtualDisplay::getDisplayDimension() const +{ + return mDisplayDimension.get(); +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h new file mode 100644 index 0000000000..09420ef629 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef _HWC2_TEST_VIRTUAL_DISPLAY_H +#define _HWC2_TEST_VIRTUAL_DISPLAY_H + +#include "Hwc2TestBuffer.h" +#include "Hwc2TestProperties.h" + +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + +class Hwc2TestVirtualDisplay { +public: + Hwc2TestVirtualDisplay(Hwc2TestCoverage coverage); + + std::string dump() const; + + int getBuffer(buffer_handle_t* outHandle, + android::base::unique_fd* outAcquireFence); + + void reset(); + bool advance(); + + UnsignedArea getDisplayDimension() const; + +private: + Hwc2TestBuffer mBuffer; + + Hwc2TestDisplayDimension mDisplayDimension; +}; + +#endif /* ifndef _HWC2_TEST_VIRTUAL_DISPLAY_H */ |