Loading libs/vr/libvrflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ sharedLibraries = [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "libbinder", "libbase", "libbufferhubqueue", Loading services/surfaceflinger/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ cc_defaults { "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.power@1.0", "libbase", "libbinder", Loading Loading @@ -67,6 +68,7 @@ cc_defaults { "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "libhidlbase", "libhidltransport", "libhwbinder", Loading @@ -90,6 +92,7 @@ filegroup { "ContainerLayer.cpp", "DisplayDevice.cpp", "DisplayHardware/ComposerHal.cpp", "DisplayHardware/DisplayIdentification.cpp", "DisplayHardware/FramebufferSurface.cpp", "DisplayHardware/HWC2.cpp", "DisplayHardware/HWComposer.cpp", Loading services/surfaceflinger/DisplayHardware/ComposerHal.cpp +47 −15 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #include "ComposerHal.h" #include <android/hardware/graphics/composer/2.2/IComposer.h> #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> #include <gui/BufferQueue.h> #include <hidl/HidlTransportUtils.h> Loading Loading @@ -172,22 +171,31 @@ Composer::Composer(const std::string& serviceName) LOG_ALWAYS_FATAL("failed to get hwcomposer service"); } mComposer->createClient( [&](const auto& tmpError, const auto& tmpClient) { if (sp<IComposer> composer_2_3 = IComposer::castFrom(mComposer)) { composer_2_3->createClient_2_3([&](const auto& tmpError, const auto& tmpClient) { if (tmpError == Error::NONE) { mClient = tmpClient; mClient_2_2 = tmpClient; mClient_2_3 = tmpClient; } }); } else { mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) { if (tmpError != Error::NONE) { return; } mClient = tmpClient; if (sp<V2_2::IComposer> composer_2_2 = V2_2::IComposer::castFrom(mComposer)) { mClient_2_2 = V2_2::IComposerClient::castFrom(mClient); LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr, "IComposer 2.2 did not return IComposerClient 2.2"); } }); if (mClient == nullptr) { LOG_ALWAYS_FATAL("failed to create composer client"); } // 2.2 support is optional sp<IComposer> composer_2_2 = IComposer::castFrom(mComposer); if (composer_2_2 != nullptr) { mClient_2_2 = IComposerClient::castFrom(mClient); LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr, "IComposer 2.2 did not return IComposerClient 2.2"); if (mClient == nullptr) { LOG_ALWAYS_FATAL("failed to create composer client"); } if (mIsUsingVrComposer) { Loading Loading @@ -957,6 +965,30 @@ Error Composer::getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatri return error; } // Composer HAL 2.3 Error Composer::getDisplayIdentificationData(Display display, uint8_t* outPort, std::vector<uint8_t>* outData) { if (!mClient_2_3) { return Error::UNSUPPORTED; } Error error = kDefaultError; mClient_2_3->getDisplayIdentificationData(display, [&](const auto& tmpError, const auto& tmpPort, const auto& tmpData) { error = tmpError; if (error != Error::NONE) { return; } *outPort = tmpPort; *outData = tmpData; }); return error; } CommandReader::~CommandReader() { resetData(); Loading services/surfaceflinger/DisplayHardware/ComposerHal.h +16 −5 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h> #include <android/hardware/graphics/common/1.1/types.h> #include <android/hardware/graphics/composer/2.2/IComposer.h> #include <android/hardware/graphics/composer/2.2/IComposerClient.h> #include <android/hardware/graphics/composer/2.3/IComposer.h> #include <android/hardware/graphics/composer/2.3/IComposerClient.h> #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> #include <gui/HdrMetadata.h> #include <math/mat4.h> Loading @@ -43,6 +43,7 @@ namespace types = hardware::graphics::common; namespace V2_1 = hardware::graphics::composer::V2_1; namespace V2_2 = hardware::graphics::composer::V2_2; namespace V2_3 = hardware::graphics::composer::V2_3; using types::V1_0::ColorTransform; using types::V1_0::Hdr; Loading @@ -61,8 +62,9 @@ using V2_1::Layer; using V2_2::CommandReaderBase; using V2_2::CommandWriterBase; using V2_2::IComposer; using V2_2::IComposerClient; using V2_3::IComposer; using V2_3::IComposerClient; using PerFrameMetadata = IComposerClient::PerFrameMetadata; using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey; Loading Loading @@ -185,6 +187,10 @@ public: virtual Error getRenderIntents(Display display, ColorMode colorMode, std::vector<RenderIntent>* outRenderIntents) = 0; virtual Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) = 0; // Composer HAL 2.3 virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort, std::vector<uint8_t>* outData) = 0; }; namespace impl { Loading Loading @@ -380,6 +386,10 @@ public: std::vector<RenderIntent>* outRenderIntents) override; Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) override; // Composer HAL 2.3 Error getDisplayIdentificationData(Display display, uint8_t* outPort, std::vector<uint8_t>* outData) override; private: class CommandWriter : public CommandWriterBase { public: Loading @@ -405,7 +415,8 @@ private: sp<V2_1::IComposer> mComposer; sp<V2_1::IComposerClient> mClient; sp<IComposerClient> mClient_2_2; sp<V2_2::IComposerClient> mClient_2_2; sp<IComposerClient> mClient_2_3; // 64KiB minus a small space for metadata such as read/write pointers static constexpr size_t kWriterInitialSize = Loading services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp 0 → 100644 +185 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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. */ #undef LOG_TAG #define LOG_TAG "DisplayIdentification" #include <algorithm> #include <cctype> #include <numeric> #include <optional> #include <log/log.h> #include "DisplayIdentification.h" namespace android { namespace { using byte_view = std::basic_string_view<uint8_t>; constexpr size_t kEdidHeaderLength = 5; std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) { if (view.size() < kEdidHeaderLength || view[0] || view[1] || view[2] || view[4]) { return {}; } return view[3]; } std::string_view parseEdidText(const byte_view& view) { std::string_view text(reinterpret_cast<const char*>(view.data()), view.size()); text = text.substr(0, text.find('\n')); if (!std::all_of(text.begin(), text.end(), ::isprint)) { ALOGW("Invalid EDID: ASCII text is not printable."); return {}; } return text; } // Big-endian 16-bit value encodes three 5-bit letters where A is 0b00001. template <size_t I> char getPnpLetter(uint16_t id) { static_assert(I < 3); const char letter = 'A' + (static_cast<uint8_t>(id >> ((2 - I) * 5)) & 0b00011111) - 1; return letter < 'A' || letter > 'Z' ? '\0' : letter; } DisplayId getEdidDisplayId(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) { return (static_cast<DisplayId>(manufacturerId) << 40) | (static_cast<DisplayId>(displayNameHash) << 8) | port; } } // namespace bool isEdid(const DisplayIdentificationData& data) { const uint8_t kMagic[] = {0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0}; return data.size() >= sizeof(kMagic) && std::equal(std::begin(kMagic), std::end(kMagic), data.begin()); } std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { constexpr size_t kMinLength = 128; if (edid.size() < kMinLength) { ALOGW("Invalid EDID: structure is truncated."); // Attempt parsing even if EDID is malformed. } else { ALOGW_IF(edid[126] != 0, "EDID extensions are currently unsupported."); ALOGW_IF(std::accumulate(edid.begin(), edid.begin() + kMinLength, static_cast<uint8_t>(0)), "Invalid EDID: structure does not checksum."); } constexpr size_t kManufacturerOffset = 8; if (edid.size() < kManufacturerOffset + sizeof(uint16_t)) { ALOGE("Invalid EDID: manufacturer ID is truncated."); return {}; } // Plug and play ID encoded as big-endian 16-bit value. const uint16_t manufacturerId = (edid[kManufacturerOffset] << 8) | edid[kManufacturerOffset + 1]; const auto pnpId = getPnpId(manufacturerId); if (!pnpId) { ALOGE("Invalid EDID: manufacturer ID is not a valid PnP ID."); return {}; } constexpr size_t kDescriptorOffset = 54; if (edid.size() < kDescriptorOffset) { ALOGE("Invalid EDID: descriptors are missing."); return {}; } byte_view view(edid.data(), edid.size()); view.remove_prefix(kDescriptorOffset); std::string_view displayName; std::string_view serialNumber; std::string_view asciiText; constexpr size_t kDescriptorCount = 4; constexpr size_t kDescriptorLength = 18; for (size_t i = 0; i < kDescriptorCount; i++) { if (view.size() < kDescriptorLength) { break; } if (const auto type = getEdidDescriptorType(view)) { byte_view descriptor(view.data(), kDescriptorLength); descriptor.remove_prefix(kEdidHeaderLength); switch (*type) { case 0xfc: displayName = parseEdidText(descriptor); break; case 0xfe: asciiText = parseEdidText(descriptor); break; case 0xff: serialNumber = parseEdidText(descriptor); break; } } view.remove_prefix(kDescriptorLength); } if (displayName.empty()) { ALOGW("Invalid EDID: falling back to serial number due to missing display name."); displayName = serialNumber; } if (displayName.empty()) { ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number."); displayName = asciiText; } if (displayName.empty()) { ALOGE("Invalid EDID: display name and fallback descriptors are missing."); return {}; } return Edid{manufacturerId, *pnpId, displayName}; } std::optional<PnpId> getPnpId(uint16_t manufacturerId) { const char a = getPnpLetter<0>(manufacturerId); const char b = getPnpLetter<1>(manufacturerId); const char c = getPnpLetter<2>(manufacturerId); return a && b && c ? std::make_optional(PnpId{a, b, c}) : std::nullopt; } std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData& data) { if (!isEdid(data)) { ALOGE("Display identification data has unknown format."); return {}; } const auto edid = parseEdid(data); if (!edid) { return {}; } // Hash display name instead of using product code or serial number, since the latter have been // observed to change on some displays with multiple inputs. const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName)); return getEdidDisplayId(port, edid->manufacturerId, hash); } } // namespace android Loading
libs/vr/libvrflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ sharedLibraries = [ "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "libbinder", "libbase", "libbufferhubqueue", Loading
services/surfaceflinger/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ cc_defaults { "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.power@1.0", "libbase", "libbinder", Loading Loading @@ -67,6 +68,7 @@ cc_defaults { "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "libhidlbase", "libhidltransport", "libhwbinder", Loading @@ -90,6 +92,7 @@ filegroup { "ContainerLayer.cpp", "DisplayDevice.cpp", "DisplayHardware/ComposerHal.cpp", "DisplayHardware/DisplayIdentification.cpp", "DisplayHardware/FramebufferSurface.cpp", "DisplayHardware/HWC2.cpp", "DisplayHardware/HWComposer.cpp", Loading
services/surfaceflinger/DisplayHardware/ComposerHal.cpp +47 −15 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #include "ComposerHal.h" #include <android/hardware/graphics/composer/2.2/IComposer.h> #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> #include <gui/BufferQueue.h> #include <hidl/HidlTransportUtils.h> Loading Loading @@ -172,22 +171,31 @@ Composer::Composer(const std::string& serviceName) LOG_ALWAYS_FATAL("failed to get hwcomposer service"); } mComposer->createClient( [&](const auto& tmpError, const auto& tmpClient) { if (sp<IComposer> composer_2_3 = IComposer::castFrom(mComposer)) { composer_2_3->createClient_2_3([&](const auto& tmpError, const auto& tmpClient) { if (tmpError == Error::NONE) { mClient = tmpClient; mClient_2_2 = tmpClient; mClient_2_3 = tmpClient; } }); } else { mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) { if (tmpError != Error::NONE) { return; } mClient = tmpClient; if (sp<V2_2::IComposer> composer_2_2 = V2_2::IComposer::castFrom(mComposer)) { mClient_2_2 = V2_2::IComposerClient::castFrom(mClient); LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr, "IComposer 2.2 did not return IComposerClient 2.2"); } }); if (mClient == nullptr) { LOG_ALWAYS_FATAL("failed to create composer client"); } // 2.2 support is optional sp<IComposer> composer_2_2 = IComposer::castFrom(mComposer); if (composer_2_2 != nullptr) { mClient_2_2 = IComposerClient::castFrom(mClient); LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr, "IComposer 2.2 did not return IComposerClient 2.2"); if (mClient == nullptr) { LOG_ALWAYS_FATAL("failed to create composer client"); } if (mIsUsingVrComposer) { Loading Loading @@ -957,6 +965,30 @@ Error Composer::getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatri return error; } // Composer HAL 2.3 Error Composer::getDisplayIdentificationData(Display display, uint8_t* outPort, std::vector<uint8_t>* outData) { if (!mClient_2_3) { return Error::UNSUPPORTED; } Error error = kDefaultError; mClient_2_3->getDisplayIdentificationData(display, [&](const auto& tmpError, const auto& tmpPort, const auto& tmpData) { error = tmpError; if (error != Error::NONE) { return; } *outPort = tmpPort; *outData = tmpData; }); return error; } CommandReader::~CommandReader() { resetData(); Loading
services/surfaceflinger/DisplayHardware/ComposerHal.h +16 −5 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h> #include <android/hardware/graphics/common/1.1/types.h> #include <android/hardware/graphics/composer/2.2/IComposer.h> #include <android/hardware/graphics/composer/2.2/IComposerClient.h> #include <android/hardware/graphics/composer/2.3/IComposer.h> #include <android/hardware/graphics/composer/2.3/IComposerClient.h> #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> #include <gui/HdrMetadata.h> #include <math/mat4.h> Loading @@ -43,6 +43,7 @@ namespace types = hardware::graphics::common; namespace V2_1 = hardware::graphics::composer::V2_1; namespace V2_2 = hardware::graphics::composer::V2_2; namespace V2_3 = hardware::graphics::composer::V2_3; using types::V1_0::ColorTransform; using types::V1_0::Hdr; Loading @@ -61,8 +62,9 @@ using V2_1::Layer; using V2_2::CommandReaderBase; using V2_2::CommandWriterBase; using V2_2::IComposer; using V2_2::IComposerClient; using V2_3::IComposer; using V2_3::IComposerClient; using PerFrameMetadata = IComposerClient::PerFrameMetadata; using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey; Loading Loading @@ -185,6 +187,10 @@ public: virtual Error getRenderIntents(Display display, ColorMode colorMode, std::vector<RenderIntent>* outRenderIntents) = 0; virtual Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) = 0; // Composer HAL 2.3 virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort, std::vector<uint8_t>* outData) = 0; }; namespace impl { Loading Loading @@ -380,6 +386,10 @@ public: std::vector<RenderIntent>* outRenderIntents) override; Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) override; // Composer HAL 2.3 Error getDisplayIdentificationData(Display display, uint8_t* outPort, std::vector<uint8_t>* outData) override; private: class CommandWriter : public CommandWriterBase { public: Loading @@ -405,7 +415,8 @@ private: sp<V2_1::IComposer> mComposer; sp<V2_1::IComposerClient> mClient; sp<IComposerClient> mClient_2_2; sp<V2_2::IComposerClient> mClient_2_2; sp<IComposerClient> mClient_2_3; // 64KiB minus a small space for metadata such as read/write pointers static constexpr size_t kWriterInitialSize = Loading
services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp 0 → 100644 +185 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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. */ #undef LOG_TAG #define LOG_TAG "DisplayIdentification" #include <algorithm> #include <cctype> #include <numeric> #include <optional> #include <log/log.h> #include "DisplayIdentification.h" namespace android { namespace { using byte_view = std::basic_string_view<uint8_t>; constexpr size_t kEdidHeaderLength = 5; std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) { if (view.size() < kEdidHeaderLength || view[0] || view[1] || view[2] || view[4]) { return {}; } return view[3]; } std::string_view parseEdidText(const byte_view& view) { std::string_view text(reinterpret_cast<const char*>(view.data()), view.size()); text = text.substr(0, text.find('\n')); if (!std::all_of(text.begin(), text.end(), ::isprint)) { ALOGW("Invalid EDID: ASCII text is not printable."); return {}; } return text; } // Big-endian 16-bit value encodes three 5-bit letters where A is 0b00001. template <size_t I> char getPnpLetter(uint16_t id) { static_assert(I < 3); const char letter = 'A' + (static_cast<uint8_t>(id >> ((2 - I) * 5)) & 0b00011111) - 1; return letter < 'A' || letter > 'Z' ? '\0' : letter; } DisplayId getEdidDisplayId(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) { return (static_cast<DisplayId>(manufacturerId) << 40) | (static_cast<DisplayId>(displayNameHash) << 8) | port; } } // namespace bool isEdid(const DisplayIdentificationData& data) { const uint8_t kMagic[] = {0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0}; return data.size() >= sizeof(kMagic) && std::equal(std::begin(kMagic), std::end(kMagic), data.begin()); } std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { constexpr size_t kMinLength = 128; if (edid.size() < kMinLength) { ALOGW("Invalid EDID: structure is truncated."); // Attempt parsing even if EDID is malformed. } else { ALOGW_IF(edid[126] != 0, "EDID extensions are currently unsupported."); ALOGW_IF(std::accumulate(edid.begin(), edid.begin() + kMinLength, static_cast<uint8_t>(0)), "Invalid EDID: structure does not checksum."); } constexpr size_t kManufacturerOffset = 8; if (edid.size() < kManufacturerOffset + sizeof(uint16_t)) { ALOGE("Invalid EDID: manufacturer ID is truncated."); return {}; } // Plug and play ID encoded as big-endian 16-bit value. const uint16_t manufacturerId = (edid[kManufacturerOffset] << 8) | edid[kManufacturerOffset + 1]; const auto pnpId = getPnpId(manufacturerId); if (!pnpId) { ALOGE("Invalid EDID: manufacturer ID is not a valid PnP ID."); return {}; } constexpr size_t kDescriptorOffset = 54; if (edid.size() < kDescriptorOffset) { ALOGE("Invalid EDID: descriptors are missing."); return {}; } byte_view view(edid.data(), edid.size()); view.remove_prefix(kDescriptorOffset); std::string_view displayName; std::string_view serialNumber; std::string_view asciiText; constexpr size_t kDescriptorCount = 4; constexpr size_t kDescriptorLength = 18; for (size_t i = 0; i < kDescriptorCount; i++) { if (view.size() < kDescriptorLength) { break; } if (const auto type = getEdidDescriptorType(view)) { byte_view descriptor(view.data(), kDescriptorLength); descriptor.remove_prefix(kEdidHeaderLength); switch (*type) { case 0xfc: displayName = parseEdidText(descriptor); break; case 0xfe: asciiText = parseEdidText(descriptor); break; case 0xff: serialNumber = parseEdidText(descriptor); break; } } view.remove_prefix(kDescriptorLength); } if (displayName.empty()) { ALOGW("Invalid EDID: falling back to serial number due to missing display name."); displayName = serialNumber; } if (displayName.empty()) { ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number."); displayName = asciiText; } if (displayName.empty()) { ALOGE("Invalid EDID: display name and fallback descriptors are missing."); return {}; } return Edid{manufacturerId, *pnpId, displayName}; } std::optional<PnpId> getPnpId(uint16_t manufacturerId) { const char a = getPnpLetter<0>(manufacturerId); const char b = getPnpLetter<1>(manufacturerId); const char c = getPnpLetter<2>(manufacturerId); return a && b && c ? std::make_optional(PnpId{a, b, c}) : std::nullopt; } std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData& data) { if (!isEdid(data)) { ALOGE("Display identification data has unknown format."); return {}; } const auto edid = parseEdid(data); if (!edid) { return {}; } // Hash display name instead of using product code or serial number, since the latter have been // observed to change on some displays with multiple inputs. const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName)); return getEdidDisplayId(port, edid->manufacturerId, hash); } } // namespace android