/* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include namespace android::display::impl { /** * Implementation of ADisplayConfig */ struct DisplayConfigImpl { /** * The ID of the display configuration. */ size_t id; /** * The width in pixels of the display configuration. */ int32_t width{0}; /** * The height in pixels of the display configuration. */ int32_t height{0}; /** * The display density. */ float density{0}; /** * The refresh rate of the display configuration, in frames per second. */ float fps{0.0}; /** * The vsync offset at which surfaceflinger runs, in nanoseconds. */ int64_t sfOffset{0}; /** * The vsync offset at which applications run, in nanoseconds. */ int64_t appOffset{0}; }; // DisplayConfigImpl allocation is not managed through C++ memory apis, so // preventing calling the destructor here. static_assert(std::is_trivially_destructible::value); /** * Implementation of ADisplay */ struct DisplayImpl { /** * A physical display ID, unique to this display. */ PhysicalDisplayId id; /** * The type of the display, i.e. whether it is an internal or external * display. */ ADisplayType type; /** * The preferred WCG dataspace */ ADataSpace wcgDataspace; /** * The preferred WCG pixel format */ AHardwareBuffer_Format wcgPixelFormat; /** * Number of supported configs */ size_t numConfigs; /** * Set of supported configs by this display. */ DisplayConfigImpl* configs; }; // DisplayImpl allocation is not managed through C++ memory apis, so // preventing calling the destructor here. static_assert(std::is_trivially_destructible::value); } // namespace android::display::impl using namespace android; using namespace android::display::impl; #define CHECK_NOT_NULL(name) \ LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument"); namespace { sp getToken(ADisplay* display) { DisplayImpl* impl = reinterpret_cast(display); return SurfaceComposerClient::getPhysicalDisplayToken(impl->id); } } // namespace namespace android { int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { const std::vector ids = SurfaceComposerClient::getPhysicalDisplayIds(); const size_t size = ids.size(); if (size == 0) { return NO_INIT; } std::vector modesPerDisplay[size]; int numModes = 0; for (int i = 0; i < size; ++i) { const sp token = SurfaceComposerClient::getPhysicalDisplayToken(ids[i]); ui::StaticDisplayInfo staticInfo; if (const status_t status = SurfaceComposerClient::getStaticDisplayInfo(token, &staticInfo); status != OK) { return status; } ui::DynamicDisplayInfo dynamicInfo; if (const status_t status = SurfaceComposerClient::getDynamicDisplayInfo(token, &dynamicInfo); status != OK) { return status; } const auto& modes = dynamicInfo.supportedDisplayModes; if (modes.empty()) { return NO_INIT; } numModes += modes.size(); modesPerDisplay[i].reserve(modes.size()); for (int j = 0; j < modes.size(); ++j) { const ui::DisplayMode& mode = modes[j]; modesPerDisplay[i].emplace_back( DisplayConfigImpl{static_cast(mode.id), mode.resolution.getWidth(), mode.resolution.getHeight(), staticInfo.density, mode.refreshRate, mode.sfVsyncOffset, mode.appVsyncOffset}); } } const std::optional internalId = SurfaceComposerClient::getInternalDisplayId(); ui::Dataspace defaultDataspace; ui::PixelFormat defaultPixelFormat; ui::Dataspace wcgDataspace; ui::PixelFormat wcgPixelFormat; const status_t status = SurfaceComposerClient::getCompositionPreference(&defaultDataspace, &defaultPixelFormat, &wcgDataspace, &wcgPixelFormat); if (status != NO_ERROR) { return status; } // Here we allocate all our required memory in one block. The layout is as // follows: // ------------------------------------------------------------ // | DisplayImpl pointers | DisplayImpls | DisplayConfigImpls | // ------------------------------------------------------------ // // The caller will be given a DisplayImpl** which points to the beginning of // the block of DisplayImpl pointers. // Each DisplayImpl* points to a DisplayImpl in the second block. // Each DisplayImpl contains a DisplayConfigImpl*, which points to a // contiguous block of DisplayConfigImpls specific to that display. DisplayImpl** const impls = reinterpret_cast( malloc((sizeof(DisplayImpl) + sizeof(DisplayImpl*)) * size + sizeof(DisplayConfigImpl) * numModes)); DisplayImpl* const displayData = reinterpret_cast(impls + size); DisplayConfigImpl* configData = reinterpret_cast(displayData + size); for (size_t i = 0; i < size; ++i) { const PhysicalDisplayId id = ids[i]; const ADisplayType type = (internalId == id) ? ADisplayType::DISPLAY_TYPE_INTERNAL : ADisplayType::DISPLAY_TYPE_EXTERNAL; const std::vector& configs = modesPerDisplay[i]; memcpy(configData, configs.data(), sizeof(DisplayConfigImpl) * configs.size()); displayData[i] = DisplayImpl{id, type, static_cast(wcgDataspace), static_cast(wcgPixelFormat), configs.size(), configData}; impls[i] = displayData + i; // Advance the configData pointer so that future configs are written to // the correct display. configData += configs.size(); } *outDisplays = reinterpret_cast(impls); return size; } void ADisplay_release(ADisplay** displays) { if (displays == nullptr) { return; } free(displays); } float ADisplay_getMaxSupportedFps(ADisplay* display) { CHECK_NOT_NULL(display); DisplayImpl* impl = reinterpret_cast(display); float maxFps = 0.0; for (int i = 0; i < impl->numConfigs; ++i) { maxFps = std::max(maxFps, impl->configs[i].fps); } return maxFps; } ADisplayType ADisplay_getDisplayType(ADisplay* display) { CHECK_NOT_NULL(display); return reinterpret_cast(display)->type; } void ADisplay_getPreferredWideColorFormat(ADisplay* display, ADataSpace* outDataspace, AHardwareBuffer_Format* outPixelFormat) { CHECK_NOT_NULL(display); CHECK_NOT_NULL(outDataspace); CHECK_NOT_NULL(outPixelFormat); DisplayImpl* impl = reinterpret_cast(display); *outDataspace = impl->wcgDataspace; *outPixelFormat = impl->wcgPixelFormat; } int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig) { CHECK_NOT_NULL(display); sp token = getToken(display); ui::DynamicDisplayInfo info; if (const auto status = SurfaceComposerClient::getDynamicDisplayInfo(token, &info); status != OK) { return status; } DisplayImpl* impl = reinterpret_cast(display); for (size_t i = 0; i < impl->numConfigs; i++) { auto* config = impl->configs + i; if (config->id == info.activeDisplayModeId) { *outConfig = reinterpret_cast(config); return OK; } } return NAME_NOT_FOUND; } float ADisplayConfig_getDensity(ADisplayConfig* config) { CHECK_NOT_NULL(config); return reinterpret_cast(config)->density; } int32_t ADisplayConfig_getWidth(ADisplayConfig* config) { CHECK_NOT_NULL(config); return reinterpret_cast(config)->width; } int32_t ADisplayConfig_getHeight(ADisplayConfig* config) { CHECK_NOT_NULL(config); return reinterpret_cast(config)->height; } float ADisplayConfig_getFps(ADisplayConfig* config) { CHECK_NOT_NULL(config); return reinterpret_cast(config)->fps; } int64_t ADisplayConfig_getCompositorOffsetNanos(ADisplayConfig* config) { CHECK_NOT_NULL(config); return reinterpret_cast(config)->sfOffset; } int64_t ADisplayConfig_getAppVsyncOffsetNanos(ADisplayConfig* config) { CHECK_NOT_NULL(config); return reinterpret_cast(config)->appOffset; } } // namespace android