summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/Android.bp1
-rw-r--r--libs/androidfw/AssetManager2.cpp18
-rw-r--r--libs/androidfw/LoadedArsc.cpp58
-rw-r--r--libs/androidfw/LocaleData.cpp14
-rw-r--r--libs/androidfw/LocaleDataTables.cpp1454
-rw-r--r--libs/androidfw/OWNERS1
-rw-r--r--libs/androidfw/ResourceTypes.cpp14
-rw-r--r--libs/androidfw/TEST_MAPPING8
-rw-r--r--libs/androidfw/include/androidfw/Chunk.h4
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h18
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h51
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp49
-rw-r--r--libs/androidfw/tests/data/overlay/overlay.apkbin5211 -> 5211 bytes
-rw-r--r--libs/androidfw/tests/data/overlayable/AndroidManifest.xml21
-rw-r--r--libs/androidfw/tests/data/overlayable/R.h42
-rwxr-xr-xlibs/androidfw/tests/data/overlayable/build22
-rw-r--r--libs/androidfw/tests/data/overlayable/overlayable.apkbin0 -> 1387 bytes
-rw-r--r--libs/androidfw/tests/data/overlayable/res/values/overlayable.xml41
-rw-r--r--libs/androidfw/tests/data/overlayable/res/values/public.xml23
-rw-r--r--libs/androidfw/tests/data/overlayable/res/values/values.xml23
-rw-r--r--libs/hwui/Android.bp9
-rw-r--r--libs/hwui/DeviceInfo.cpp46
-rw-r--r--libs/hwui/DeviceInfo.h7
-rw-r--r--libs/hwui/DisplayListOps.in7
-rw-r--r--libs/hwui/HWUIProperties.sysprop9
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp16
-rw-r--r--libs/hwui/HardwareBitmapUploader.h1
-rw-r--r--libs/hwui/Matrix.h2
-rw-r--r--libs/hwui/Properties.cpp35
-rw-r--r--libs/hwui/Properties.h32
-rw-r--r--libs/hwui/RecordingCanvas.cpp118
-rw-r--r--libs/hwui/RecordingCanvas.h13
-rw-r--r--libs/hwui/Rect.h8
-rw-r--r--libs/hwui/RenderNode.cpp15
-rw-r--r--libs/hwui/RenderProperties.h6
-rw-r--r--libs/hwui/SkiaCanvas.cpp26
-rw-r--r--libs/hwui/SkiaCanvas.h5
-rw-r--r--libs/hwui/WebViewFunctorManager.cpp175
-rw-r--r--libs/hwui/WebViewFunctorManager.h93
-rw-r--r--libs/hwui/debug/GlesErrorCheckWrapper.h2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp85
-rw-r--r--libs/hwui/hwui/Bitmap.h44
-rw-r--r--libs/hwui/hwui/Canvas.cpp4
-rw-r--r--libs/hwui/hwui/Canvas.h10
-rw-r--r--libs/hwui/hwui/MinikinSkia.cpp2
-rw-r--r--libs/hwui/hwui/Paint.h2
-rw-r--r--libs/hwui/pipeline/skia/DumpOpsCanvas.h17
-rw-r--r--libs/hwui/pipeline/skia/FunctorDrawable.h36
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp41
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.h6
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp20
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.h4
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.cpp7
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.cpp16
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.h8
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.cpp4
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.h6
-rw-r--r--libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp22
-rw-r--r--libs/hwui/pipeline/skia/SkiaMemoryTracer.h4
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp13
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp24
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h7
-rw-r--r--libs/hwui/pipeline/skia/SkiaProfileRenderer.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp34
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h1
-rw-r--r--libs/hwui/pipeline/skia/SkiaUtils.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp16
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h4
-rw-r--r--libs/hwui/pipeline/skia/VectorDrawableAtlas.h4
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.cpp85
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.h65
-rw-r--r--libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp114
-rw-r--r--libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h12
-rw-r--r--libs/hwui/private/hwui/DrawVkInfo.h107
-rw-r--r--libs/hwui/private/hwui/WebViewFunctor.h83
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp29
-rw-r--r--libs/hwui/renderthread/CacheManager.h2
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp50
-rw-r--r--libs/hwui/renderthread/CanvasContext.h3
-rw-r--r--libs/hwui/renderthread/EglManager.cpp186
-rw-r--r--libs/hwui/renderthread/EglManager.h18
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h6
-rw-r--r--libs/hwui/renderthread/ReliableSurface.cpp318
-rw-r--r--libs/hwui/renderthread/ReliableSurface.h87
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp9
-rw-r--r--libs/hwui/renderthread/RenderProxy.h1
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp5
-rw-r--r--libs/hwui/renderthread/RenderThread.h5
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp37
-rw-r--r--libs/hwui/renderthread/VulkanManager.h15
-rw-r--r--libs/hwui/service/GraphicsStatsService.cpp10
-rw-r--r--libs/hwui/surfacetexture/ImageConsumer.cpp3
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp28
-rw-r--r--libs/hwui/tests/common/TestUtils.h62
-rw-r--r--libs/hwui/tests/common/scenes/BitmapFillrate.cpp4
-rw-r--r--libs/hwui/tests/common/scenes/BitmapShaders.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/ListViewAnimation.cpp12
-rw-r--r--libs/hwui/tests/common/scenes/ShapeAnimation.cpp2
-rw-r--r--libs/hwui/tests/common/scenes/TvApp.cpp8
-rw-r--r--libs/hwui/tests/macrobench/main.cpp5
-rw-r--r--libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp2
-rw-r--r--libs/hwui/tests/unit/FatalTestCanvas.h18
-rw-r--r--libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp2
-rw-r--r--libs/hwui/tests/unit/RenderNodeDrawableTests.cpp58
-rw-r--r--libs/hwui/tests/unit/RenderNodeTests.cpp4
-rw-r--r--libs/hwui/tests/unit/ShaderCacheTests.cpp99
-rw-r--r--libs/hwui/tests/unit/SkiaDisplayListTests.cpp27
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp38
-rw-r--r--libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp2
-rw-r--r--libs/hwui/tests/unit/ThreadBaseTests.cpp4
-rw-r--r--libs/hwui/tests/unit/TypefaceTests.cpp6
-rw-r--r--libs/hwui/tests/unit/VectorDrawableTests.cpp41
-rw-r--r--libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp154
-rw-r--r--libs/hwui/tests/unit/main.cpp4
-rw-r--r--libs/hwui/thread/ThreadBase.h2
-rw-r--r--libs/hwui/utils/Color.h3
-rw-r--r--libs/hwui/utils/LinearAllocator.h2
-rw-r--r--libs/incident/include/android/os/IncidentReportArgs.h2
-rw-r--r--libs/incident/proto/android/os/metadata.proto4
-rw-r--r--libs/incident/src/IncidentReportArgs.cpp2
-rw-r--r--libs/input/Android.bp1
-rw-r--r--libs/input/PointerController.cpp137
-rw-r--r--libs/input/PointerController.h12
-rw-r--r--libs/input/SpriteController.cpp24
-rw-r--r--libs/input/SpriteController.h8
-rw-r--r--libs/protoutil/include/android/util/EncodedBuffer.h6
128 files changed, 3321 insertions, 1650 deletions
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 98af3eb05391..eeaefc5b157c 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -167,6 +167,7 @@ cc_test {
},
},
data: ["tests/data/**/*.apk"],
+ test_suites: ["device-tests"],
}
cc_benchmark {
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 7ab12b1b3167..ad9ec02648b1 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -217,10 +217,19 @@ std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_
ATRACE_NAME("AssetManager::GetResourceConfigurations");
std::set<ResTable_config> configurations;
for (const PackageGroup& package_group : package_groups_) {
+ bool found_system_package = false;
for (const ConfiguredPackage& package : package_group.packages_) {
if (exclude_system && package.loaded_package_->IsSystem()) {
+ found_system_package = true;
continue;
}
+
+ if (exclude_system && package.loaded_package_->IsOverlay() && found_system_package) {
+ // Overlays must appear after the target package to take effect. Any overlay found in the
+ // same package as a system package is able to overlay system resources.
+ continue;
+ }
+
package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
}
}
@@ -232,10 +241,19 @@ std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
ATRACE_NAME("AssetManager::GetResourceLocales");
std::set<std::string> locales;
for (const PackageGroup& package_group : package_groups_) {
+ bool found_system_package = false;
for (const ConfiguredPackage& package : package_group.packages_) {
if (exclude_system && package.loaded_package_->IsSystem()) {
+ found_system_package = true;
continue;
}
+
+ if (exclude_system && package.loaded_package_->IsOverlay() && found_system_package) {
+ // Overlays must appear after the target package to take effect. Any overlay found in the
+ // same package as a system package is able to overlay system resources.
+ continue;
+ }
+
package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales);
}
}
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 68d216d286cf..5a267804ddf1 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -583,7 +583,65 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
loaded_package->dynamic_package_map_.emplace_back(std::move(package_name),
dtohl(entry_iter->packageId));
}
+ } break;
+
+ case RES_TABLE_OVERLAYABLE_TYPE: {
+ const ResTable_overlayable_header* header =
+ child_chunk.header<ResTable_overlayable_header>();
+ if (header == nullptr) {
+ LOG(ERROR) << "RES_TABLE_OVERLAYABLE_TYPE too small.";
+ return {};
+ }
+
+ // Iterate over the overlayable policy chunks
+ ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
+ while (overlayable_iter.HasNext()) {
+ const Chunk overlayable_child_chunk = overlayable_iter.Next();
+
+ switch (overlayable_child_chunk.type()) {
+ case RES_TABLE_OVERLAYABLE_POLICY_TYPE: {
+ const ResTable_overlayable_policy_header* policy_header =
+ overlayable_child_chunk.header<ResTable_overlayable_policy_header>();
+ if (policy_header == nullptr) {
+ LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small.";
+ return {};
+ }
+
+ if ((overlayable_child_chunk.data_size() / sizeof(ResTable_ref))
+ < dtohl(policy_header->entry_count)) {
+ LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small to hold entries.";
+ return {};
+ }
+
+ // Retrieve all the ids belonging to this policy
+ std::unordered_set<uint32_t> ids;
+ const auto ids_begin =
+ reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
+ const auto ids_end = ids_begin + dtohl(policy_header->entry_count);
+ for (auto id_iter = ids_begin; id_iter != ids_end; ++id_iter) {
+ ids.insert(dtohl(id_iter->ident));
+ }
+
+ // Add the pairing of overlayable properties to resource ids to the package
+ OverlayableInfo overlayable_info{};
+ overlayable_info.policy_flags = policy_header->policy_flags;
+ loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
+ break;
+ }
+
+ default:
+ LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+ break;
+ }
+ }
+ if (overlayable_iter.HadError()) {
+ LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s",
+ overlayable_iter.GetLastError().c_str());
+ if (overlayable_iter.HadFatalError()) {
+ return {};
+ }
+ }
} break;
default:
diff --git a/libs/androidfw/LocaleData.cpp b/libs/androidfw/LocaleData.cpp
index 889d166d853b..020cef6012e9 100644
--- a/libs/androidfw/LocaleData.cpp
+++ b/libs/androidfw/LocaleData.cpp
@@ -34,11 +34,11 @@ inline uint32_t packLocale(const char* language, const char* region) {
}
inline uint32_t dropRegion(uint32_t packed_locale) {
- return packed_locale & 0xFFFF0000lu;
+ return packed_locale & 0xFFFF0000LU;
}
inline bool hasRegion(uint32_t packed_locale) {
- return (packed_locale & 0x0000FFFFlu) != 0;
+ return (packed_locale & 0x0000FFFFLU) != 0;
}
const size_t SCRIPT_LENGTH = 4;
@@ -122,9 +122,9 @@ inline bool isRepresentative(uint32_t language_and_region, const char* script) {
return (REPRESENTATIVE_LOCALES.count(packed_locale) != 0);
}
-const uint32_t US_SPANISH = 0x65735553lu; // es-US
-const uint32_t MEXICAN_SPANISH = 0x65734D58lu; // es-MX
-const uint32_t LATIN_AMERICAN_SPANISH = 0x6573A424lu; // es-419
+const uint32_t US_SPANISH = 0x65735553LU; // es-US
+const uint32_t MEXICAN_SPANISH = 0x65734D58LU; // es-MX
+const uint32_t LATIN_AMERICAN_SPANISH = 0x6573A424LU; // es-419
// The two locales es-US and es-MX are treated as special fallbacks for es-419.
// If there is no es-419, they are considered its equivalent.
@@ -225,8 +225,8 @@ void localeDataComputeScript(char out[4], const char* language, const char* regi
}
const uint32_t ENGLISH_STOP_LIST[2] = {
- 0x656E0000lu, // en
- 0x656E8400lu, // en-001
+ 0x656E0000LU, // en
+ 0x656E8400LU, // en-001
};
const char ENGLISH_CHARS[2] = {'e', 'n'};
const char LATIN_CHARS[4] = {'L', 'a', 't', 'n'};
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 7c381efec7ec..c276a238e2e1 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -1446,733 +1446,733 @@ const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
});
std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
- 0x616145544C61746Ellu, // aa_Latn_ET
- 0x616247454379726Cllu, // ab_Cyrl_GE
- 0xC42047484C61746Ellu, // abr_Latn_GH
- 0x904049444C61746Ellu, // ace_Latn_ID
- 0x9C4055474C61746Ellu, // ach_Latn_UG
- 0x806047484C61746Ellu, // ada_Latn_GH
- 0xE06052554379726Cllu, // ady_Cyrl_RU
- 0x6165495241767374llu, // ae_Avst_IR
- 0x8480544E41726162llu, // aeb_Arab_TN
- 0x61665A414C61746Ellu, // af_Latn_ZA
- 0xC0C0434D4C61746Ellu, // agq_Latn_CM
- 0xB8E0494E41686F6Dllu, // aho_Ahom_IN
- 0x616B47484C61746Ellu, // ak_Latn_GH
- 0xA940495158737578llu, // akk_Xsux_IQ
- 0xB560584B4C61746Ellu, // aln_Latn_XK
- 0xCD6052554379726Cllu, // alt_Cyrl_RU
- 0x616D455445746869llu, // am_Ethi_ET
- 0xB9804E474C61746Ellu, // amo_Latn_NG
- 0xE5C049444C61746Ellu, // aoz_Latn_ID
- 0x8DE0544741726162llu, // apd_Arab_TG
- 0x6172454741726162llu, // ar_Arab_EG
- 0x8A20495241726D69llu, // arc_Armi_IR
- 0x8A204A4F4E626174llu, // arc_Nbat_JO
- 0x8A20535950616C6Dllu, // arc_Palm_SY
- 0xB620434C4C61746Ellu, // arn_Latn_CL
- 0xBA20424F4C61746Ellu, // aro_Latn_BO
- 0xC220445A41726162llu, // arq_Arab_DZ
- 0xE2204D4141726162llu, // ary_Arab_MA
- 0xE620454741726162llu, // arz_Arab_EG
- 0x6173494E42656E67llu, // as_Beng_IN
- 0x8240545A4C61746Ellu, // asa_Latn_TZ
- 0x9240555353676E77llu, // ase_Sgnw_US
- 0xCE4045534C61746Ellu, // ast_Latn_ES
- 0xA66043414C61746Ellu, // atj_Latn_CA
- 0x617652554379726Cllu, // av_Cyrl_RU
- 0x82C0494E44657661llu, // awa_Deva_IN
- 0x6179424F4C61746Ellu, // ay_Latn_BO
- 0x617A495241726162llu, // az_Arab_IR
- 0x617A415A4C61746Ellu, // az_Latn_AZ
- 0x626152554379726Cllu, // ba_Cyrl_RU
- 0xAC01504B41726162llu, // bal_Arab_PK
- 0xB40149444C61746Ellu, // ban_Latn_ID
- 0xBC014E5044657661llu, // bap_Deva_NP
- 0xC40141544C61746Ellu, // bar_Latn_AT
- 0xC801434D4C61746Ellu, // bas_Latn_CM
- 0xDC01434D42616D75llu, // bax_Bamu_CM
- 0x882149444C61746Ellu, // bbc_Latn_ID
- 0xA421434D4C61746Ellu, // bbj_Latn_CM
- 0xA04143494C61746Ellu, // bci_Latn_CI
- 0x626542594379726Cllu, // be_Cyrl_BY
- 0xA481534441726162llu, // bej_Arab_SD
- 0xB0815A4D4C61746Ellu, // bem_Latn_ZM
- 0xD88149444C61746Ellu, // bew_Latn_ID
- 0xE481545A4C61746Ellu, // bez_Latn_TZ
- 0x8CA1434D4C61746Ellu, // bfd_Latn_CM
- 0xC0A1494E54616D6Cllu, // bfq_Taml_IN
- 0xCCA1504B41726162llu, // bft_Arab_PK
- 0xE0A1494E44657661llu, // bfy_Deva_IN
- 0x626742474379726Cllu, // bg_Cyrl_BG
- 0x88C1494E44657661llu, // bgc_Deva_IN
- 0xB4C1504B41726162llu, // bgn_Arab_PK
- 0xDCC154524772656Bllu, // bgx_Grek_TR
- 0x84E1494E44657661llu, // bhb_Deva_IN
- 0xA0E1494E44657661llu, // bhi_Deva_IN
- 0xA8E150484C61746Ellu, // bhk_Latn_PH
- 0xB8E1494E44657661llu, // bho_Deva_IN
- 0x626956554C61746Ellu, // bi_Latn_VU
- 0xA90150484C61746Ellu, // bik_Latn_PH
- 0xB5014E474C61746Ellu, // bin_Latn_NG
- 0xA521494E44657661llu, // bjj_Deva_IN
- 0xB52149444C61746Ellu, // bjn_Latn_ID
- 0xB141434D4C61746Ellu, // bkm_Latn_CM
- 0xD14150484C61746Ellu, // bku_Latn_PH
- 0xCD61564E54617674llu, // blt_Tavt_VN
- 0x626D4D4C4C61746Ellu, // bm_Latn_ML
- 0xC1814D4C4C61746Ellu, // bmq_Latn_ML
- 0x626E424442656E67llu, // bn_Beng_BD
- 0x626F434E54696274llu, // bo_Tibt_CN
- 0xE1E1494E42656E67llu, // bpy_Beng_IN
- 0xA201495241726162llu, // bqi_Arab_IR
- 0xD60143494C61746Ellu, // bqv_Latn_CI
- 0x627246524C61746Ellu, // br_Latn_FR
- 0x8221494E44657661llu, // bra_Deva_IN
- 0x9E21504B41726162llu, // brh_Arab_PK
- 0xDE21494E44657661llu, // brx_Deva_IN
- 0x627342414C61746Ellu, // bs_Latn_BA
- 0xC2414C5242617373llu, // bsq_Bass_LR
- 0xCA41434D4C61746Ellu, // bss_Latn_CM
- 0xBA6150484C61746Ellu, // bto_Latn_PH
- 0xD661504B44657661llu, // btv_Deva_PK
- 0x828152554379726Cllu, // bua_Cyrl_RU
- 0x8A8159544C61746Ellu, // buc_Latn_YT
- 0x9A8149444C61746Ellu, // bug_Latn_ID
- 0xB281434D4C61746Ellu, // bum_Latn_CM
- 0x86A147514C61746Ellu, // bvb_Latn_GQ
- 0xB701455245746869llu, // byn_Ethi_ER
- 0xD701434D4C61746Ellu, // byv_Latn_CM
- 0x93214D4C4C61746Ellu, // bze_Latn_ML
- 0x636145534C61746Ellu, // ca_Latn_ES
- 0x9C424E474C61746Ellu, // cch_Latn_NG
- 0xBC42494E42656E67llu, // ccp_Beng_IN
- 0xBC42424443616B6Dllu, // ccp_Cakm_BD
- 0x636552554379726Cllu, // ce_Cyrl_RU
- 0x848250484C61746Ellu, // ceb_Latn_PH
- 0x98C255474C61746Ellu, // cgg_Latn_UG
- 0x636847554C61746Ellu, // ch_Latn_GU
- 0xA8E2464D4C61746Ellu, // chk_Latn_FM
- 0xB0E252554379726Cllu, // chm_Cyrl_RU
- 0xB8E255534C61746Ellu, // cho_Latn_US
- 0xBCE243414C61746Ellu, // chp_Latn_CA
- 0xC4E2555343686572llu, // chr_Cher_US
- 0x81224B4841726162llu, // cja_Arab_KH
- 0xB122564E4368616Dllu, // cjm_Cham_VN
- 0x8542495141726162llu, // ckb_Arab_IQ
- 0x636F46524C61746Ellu, // co_Latn_FR
- 0xBDC24547436F7074llu, // cop_Copt_EG
- 0xC9E250484C61746Ellu, // cps_Latn_PH
- 0x6372434143616E73llu, // cr_Cans_CA
- 0xA622434143616E73llu, // crj_Cans_CA
- 0xAA22434143616E73llu, // crk_Cans_CA
- 0xAE22434143616E73llu, // crl_Cans_CA
- 0xB222434143616E73llu, // crm_Cans_CA
- 0xCA2253434C61746Ellu, // crs_Latn_SC
- 0x6373435A4C61746Ellu, // cs_Latn_CZ
- 0x8642504C4C61746Ellu, // csb_Latn_PL
- 0xDA42434143616E73llu, // csw_Cans_CA
- 0x8E624D4D50617563llu, // ctd_Pauc_MM
- 0x637552554379726Cllu, // cu_Cyrl_RU
- 0x63754247476C6167llu, // cu_Glag_BG
- 0x637652554379726Cllu, // cv_Cyrl_RU
- 0x637947424C61746Ellu, // cy_Latn_GB
- 0x6461444B4C61746Ellu, // da_Latn_DK
- 0xA80355534C61746Ellu, // dak_Latn_US
- 0xC40352554379726Cllu, // dar_Cyrl_RU
- 0xD4034B454C61746Ellu, // dav_Latn_KE
- 0x8843494E41726162llu, // dcc_Arab_IN
- 0x646544454C61746Ellu, // de_Latn_DE
- 0xB48343414C61746Ellu, // den_Latn_CA
- 0xC4C343414C61746Ellu, // dgr_Latn_CA
- 0x91234E454C61746Ellu, // dje_Latn_NE
- 0xA5A343494C61746Ellu, // dnj_Latn_CI
- 0xA1C3494E41726162llu, // doi_Arab_IN
- 0x864344454C61746Ellu, // dsb_Latn_DE
- 0xB2634D4C4C61746Ellu, // dtm_Latn_ML
- 0xBE634D594C61746Ellu, // dtp_Latn_MY
- 0xE2634E5044657661llu, // dty_Deva_NP
- 0x8283434D4C61746Ellu, // dua_Latn_CM
- 0x64764D5654686161llu, // dv_Thaa_MV
- 0xBB03534E4C61746Ellu, // dyo_Latn_SN
- 0xD30342464C61746Ellu, // dyu_Latn_BF
- 0x647A425454696274llu, // dz_Tibt_BT
- 0xD0244B454C61746Ellu, // ebu_Latn_KE
- 0x656547484C61746Ellu, // ee_Latn_GH
- 0xA0A44E474C61746Ellu, // efi_Latn_NG
- 0xACC449544C61746Ellu, // egl_Latn_IT
- 0xE0C4454745677970llu, // egy_Egyp_EG
- 0xE1444D4D4B616C69llu, // eky_Kali_MM
- 0x656C47524772656Bllu, // el_Grek_GR
- 0x656E47424C61746Ellu, // en_Latn_GB
- 0x656E55534C61746Ellu, // en_Latn_US
- 0x656E474253686177llu, // en_Shaw_GB
- 0x657345534C61746Ellu, // es_Latn_ES
- 0x65734D584C61746Ellu, // es_Latn_MX
- 0x657355534C61746Ellu, // es_Latn_US
- 0xD24455534C61746Ellu, // esu_Latn_US
- 0x657445454C61746Ellu, // et_Latn_EE
- 0xCE6449544974616Cllu, // ett_Ital_IT
- 0x657545534C61746Ellu, // eu_Latn_ES
- 0xBAC4434D4C61746Ellu, // ewo_Latn_CM
- 0xCEE445534C61746Ellu, // ext_Latn_ES
- 0x6661495241726162llu, // fa_Arab_IR
- 0xB40547514C61746Ellu, // fan_Latn_GQ
- 0x6666474E41646C6Dllu, // ff_Adlm_GN
- 0x6666534E4C61746Ellu, // ff_Latn_SN
- 0xB0A54D4C4C61746Ellu, // ffm_Latn_ML
- 0x666946494C61746Ellu, // fi_Latn_FI
- 0x8105534441726162llu, // fia_Arab_SD
- 0xAD0550484C61746Ellu, // fil_Latn_PH
- 0xCD0553454C61746Ellu, // fit_Latn_SE
- 0x666A464A4C61746Ellu, // fj_Latn_FJ
- 0x666F464F4C61746Ellu, // fo_Latn_FO
- 0xB5C5424A4C61746Ellu, // fon_Latn_BJ
- 0x667246524C61746Ellu, // fr_Latn_FR
- 0x8A2555534C61746Ellu, // frc_Latn_US
- 0xBE2546524C61746Ellu, // frp_Latn_FR
- 0xC62544454C61746Ellu, // frr_Latn_DE
- 0xCA2544454C61746Ellu, // frs_Latn_DE
- 0x8685434D41726162llu, // fub_Arab_CM
- 0x8E8557464C61746Ellu, // fud_Latn_WF
- 0x9685474E4C61746Ellu, // fuf_Latn_GN
- 0xC2854E454C61746Ellu, // fuq_Latn_NE
- 0xC68549544C61746Ellu, // fur_Latn_IT
- 0xD6854E474C61746Ellu, // fuv_Latn_NG
- 0xC6A553444C61746Ellu, // fvr_Latn_SD
- 0x66794E4C4C61746Ellu, // fy_Latn_NL
- 0x676149454C61746Ellu, // ga_Latn_IE
- 0x800647484C61746Ellu, // gaa_Latn_GH
- 0x98064D444C61746Ellu, // gag_Latn_MD
- 0xB406434E48616E73llu, // gan_Hans_CN
- 0xE00649444C61746Ellu, // gay_Latn_ID
- 0xB026494E44657661llu, // gbm_Deva_IN
- 0xE426495241726162llu, // gbz_Arab_IR
- 0xC44647464C61746Ellu, // gcr_Latn_GF
- 0x676447424C61746Ellu, // gd_Latn_GB
- 0xE486455445746869llu, // gez_Ethi_ET
- 0xB4C64E5044657661llu, // ggn_Deva_NP
- 0xAD064B494C61746Ellu, // gil_Latn_KI
- 0xA926504B41726162llu, // gjk_Arab_PK
- 0xD126504B41726162llu, // gju_Arab_PK
- 0x676C45534C61746Ellu, // gl_Latn_ES
- 0xA966495241726162llu, // glk_Arab_IR
- 0x676E50594C61746Ellu, // gn_Latn_PY
- 0xB1C6494E44657661llu, // gom_Deva_IN
- 0xB5C6494E54656C75llu, // gon_Telu_IN
- 0xC5C649444C61746Ellu, // gor_Latn_ID
- 0xC9C64E4C4C61746Ellu, // gos_Latn_NL
- 0xCDC65541476F7468llu, // got_Goth_UA
- 0x8A26435943707274llu, // grc_Cprt_CY
- 0x8A2647524C696E62llu, // grc_Linb_GR
- 0xCE26494E42656E67llu, // grt_Beng_IN
- 0xDA4643484C61746Ellu, // gsw_Latn_CH
- 0x6775494E47756A72llu, // gu_Gujr_IN
- 0x868642524C61746Ellu, // gub_Latn_BR
- 0x8A86434F4C61746Ellu, // guc_Latn_CO
- 0xC68647484C61746Ellu, // gur_Latn_GH
- 0xE6864B454C61746Ellu, // guz_Latn_KE
- 0x6776494D4C61746Ellu, // gv_Latn_IM
- 0xC6A64E5044657661llu, // gvr_Deva_NP
- 0xA2C643414C61746Ellu, // gwi_Latn_CA
- 0x68614E474C61746Ellu, // ha_Latn_NG
- 0xA807434E48616E73llu, // hak_Hans_CN
- 0xD80755534C61746Ellu, // haw_Latn_US
- 0xE407414641726162llu, // haz_Arab_AF
- 0x6865494C48656272llu, // he_Hebr_IL
- 0x6869494E44657661llu, // hi_Deva_IN
- 0x9507464A4C61746Ellu, // hif_Latn_FJ
- 0xAD0750484C61746Ellu, // hil_Latn_PH
- 0xD1675452486C7577llu, // hlu_Hluw_TR
- 0x8D87434E506C7264llu, // hmd_Plrd_CN
- 0x8DA7504B41726162llu, // hnd_Arab_PK
- 0x91A7494E44657661llu, // hne_Deva_IN
- 0xA5A74C41486D6E67llu, // hnj_Hmng_LA
- 0xB5A750484C61746Ellu, // hnn_Latn_PH
- 0xB9A7504B41726162llu, // hno_Arab_PK
- 0x686F50474C61746Ellu, // ho_Latn_PG
- 0x89C7494E44657661llu, // hoc_Deva_IN
- 0xA5C7494E44657661llu, // hoj_Deva_IN
- 0x687248524C61746Ellu, // hr_Latn_HR
- 0x864744454C61746Ellu, // hsb_Latn_DE
- 0xB647434E48616E73llu, // hsn_Hans_CN
- 0x687448544C61746Ellu, // ht_Latn_HT
- 0x687548554C61746Ellu, // hu_Latn_HU
- 0x6879414D41726D6Ellu, // hy_Armn_AM
- 0x687A4E414C61746Ellu, // hz_Latn_NA
- 0x696146524C61746Ellu, // ia_Latn_FR
- 0x80284D594C61746Ellu, // iba_Latn_MY
- 0x84284E474C61746Ellu, // ibb_Latn_NG
- 0x696449444C61746Ellu, // id_Latn_ID
- 0x69674E474C61746Ellu, // ig_Latn_NG
- 0x6969434E59696969llu, // ii_Yiii_CN
- 0x696B55534C61746Ellu, // ik_Latn_US
- 0xCD4843414C61746Ellu, // ikt_Latn_CA
- 0xB96850484C61746Ellu, // ilo_Latn_PH
- 0x696E49444C61746Ellu, // in_Latn_ID
- 0x9DA852554379726Cllu, // inh_Cyrl_RU
- 0x697349534C61746Ellu, // is_Latn_IS
- 0x697449544C61746Ellu, // it_Latn_IT
- 0x6975434143616E73llu, // iu_Cans_CA
- 0x6977494C48656272llu, // iw_Hebr_IL
- 0x9F2852554C61746Ellu, // izh_Latn_RU
- 0x6A614A504A70616Ellu, // ja_Jpan_JP
- 0xB0094A4D4C61746Ellu, // jam_Latn_JM
- 0xB8C9434D4C61746Ellu, // jgo_Latn_CM
- 0x8989545A4C61746Ellu, // jmc_Latn_TZ
- 0xAD894E5044657661llu, // jml_Deva_NP
- 0xCE89444B4C61746Ellu, // jut_Latn_DK
- 0x6A7649444C61746Ellu, // jv_Latn_ID
- 0x6A7749444C61746Ellu, // jw_Latn_ID
- 0x6B61474547656F72llu, // ka_Geor_GE
- 0x800A555A4379726Cllu, // kaa_Cyrl_UZ
- 0x840A445A4C61746Ellu, // kab_Latn_DZ
- 0x880A4D4D4C61746Ellu, // kac_Latn_MM
- 0xA40A4E474C61746Ellu, // kaj_Latn_NG
- 0xB00A4B454C61746Ellu, // kam_Latn_KE
- 0xB80A4D4C4C61746Ellu, // kao_Latn_ML
- 0x8C2A52554379726Cllu, // kbd_Cyrl_RU
- 0xE02A4E4541726162llu, // kby_Arab_NE
- 0x984A4E474C61746Ellu, // kcg_Latn_NG
- 0xA84A5A574C61746Ellu, // kck_Latn_ZW
- 0x906A545A4C61746Ellu, // kde_Latn_TZ
- 0x9C6A544741726162llu, // kdh_Arab_TG
- 0xCC6A544854686169llu, // kdt_Thai_TH
- 0x808A43564C61746Ellu, // kea_Latn_CV
- 0xB48A434D4C61746Ellu, // ken_Latn_CM
- 0xB8AA43494C61746Ellu, // kfo_Latn_CI
- 0xC4AA494E44657661llu, // kfr_Deva_IN
- 0xE0AA494E44657661llu, // kfy_Deva_IN
- 0x6B6743444C61746Ellu, // kg_Latn_CD
- 0x90CA49444C61746Ellu, // kge_Latn_ID
- 0xBCCA42524C61746Ellu, // kgp_Latn_BR
- 0x80EA494E4C61746Ellu, // kha_Latn_IN
- 0x84EA434E54616C75llu, // khb_Talu_CN
- 0xB4EA494E44657661llu, // khn_Deva_IN
- 0xC0EA4D4C4C61746Ellu, // khq_Latn_ML
- 0xCCEA494E4D796D72llu, // kht_Mymr_IN
- 0xD8EA504B41726162llu, // khw_Arab_PK
- 0x6B694B454C61746Ellu, // ki_Latn_KE
- 0xD10A54524C61746Ellu, // kiu_Latn_TR
- 0x6B6A4E414C61746Ellu, // kj_Latn_NA
- 0x992A4C414C616F6Fllu, // kjg_Laoo_LA
- 0x6B6B434E41726162llu, // kk_Arab_CN
- 0x6B6B4B5A4379726Cllu, // kk_Cyrl_KZ
- 0xA54A434D4C61746Ellu, // kkj_Latn_CM
- 0x6B6C474C4C61746Ellu, // kl_Latn_GL
- 0xB56A4B454C61746Ellu, // kln_Latn_KE
- 0x6B6D4B484B686D72llu, // km_Khmr_KH
- 0x858A414F4C61746Ellu, // kmb_Latn_AO
- 0x6B6E494E4B6E6461llu, // kn_Knda_IN
- 0x6B6F4B524B6F7265llu, // ko_Kore_KR
- 0xA1CA52554379726Cllu, // koi_Cyrl_RU
- 0xA9CA494E44657661llu, // kok_Deva_IN
- 0xC9CA464D4C61746Ellu, // kos_Latn_FM
- 0x91EA4C524C61746Ellu, // kpe_Latn_LR
- 0x8A2A52554379726Cllu, // krc_Cyrl_RU
- 0xA22A534C4C61746Ellu, // kri_Latn_SL
- 0xA62A50484C61746Ellu, // krj_Latn_PH
- 0xAE2A52554C61746Ellu, // krl_Latn_RU
- 0xD22A494E44657661llu, // kru_Deva_IN
- 0x6B73494E41726162llu, // ks_Arab_IN
- 0x864A545A4C61746Ellu, // ksb_Latn_TZ
- 0x964A434D4C61746Ellu, // ksf_Latn_CM
- 0x9E4A44454C61746Ellu, // ksh_Latn_DE
- 0x6B75495141726162llu, // ku_Arab_IQ
- 0x6B7554524C61746Ellu, // ku_Latn_TR
- 0xB28A52554379726Cllu, // kum_Cyrl_RU
- 0x6B7652554379726Cllu, // kv_Cyrl_RU
- 0xC6AA49444C61746Ellu, // kvr_Latn_ID
- 0xDEAA504B41726162llu, // kvx_Arab_PK
- 0x6B7747424C61746Ellu, // kw_Latn_GB
- 0xB2EA544854686169llu, // kxm_Thai_TH
- 0xBEEA504B41726162llu, // kxp_Arab_PK
- 0x6B79434E41726162llu, // ky_Arab_CN
- 0x6B794B474379726Cllu, // ky_Cyrl_KG
- 0x6B7954524C61746Ellu, // ky_Latn_TR
- 0x6C6156414C61746Ellu, // la_Latn_VA
- 0x840B47524C696E61llu, // lab_Lina_GR
- 0x8C0B494C48656272llu, // lad_Hebr_IL
- 0x980B545A4C61746Ellu, // lag_Latn_TZ
- 0x9C0B504B41726162llu, // lah_Arab_PK
- 0xA40B55474C61746Ellu, // laj_Latn_UG
- 0x6C624C554C61746Ellu, // lb_Latn_LU
- 0x902B52554379726Cllu, // lbe_Cyrl_RU
- 0xD82B49444C61746Ellu, // lbw_Latn_ID
- 0xBC4B434E54686169llu, // lcp_Thai_CN
- 0xBC8B494E4C657063llu, // lep_Lepc_IN
- 0xE48B52554379726Cllu, // lez_Cyrl_RU
- 0x6C6755474C61746Ellu, // lg_Latn_UG
- 0x6C694E4C4C61746Ellu, // li_Latn_NL
- 0x950B4E5044657661llu, // lif_Deva_NP
- 0x950B494E4C696D62llu, // lif_Limb_IN
- 0xA50B49544C61746Ellu, // lij_Latn_IT
- 0xC90B434E4C697375llu, // lis_Lisu_CN
- 0xBD2B49444C61746Ellu, // ljp_Latn_ID
- 0xA14B495241726162llu, // lki_Arab_IR
- 0xCD4B55534C61746Ellu, // lkt_Latn_US
- 0xB58B494E54656C75llu, // lmn_Telu_IN
- 0xB98B49544C61746Ellu, // lmo_Latn_IT
- 0x6C6E43444C61746Ellu, // ln_Latn_CD
- 0x6C6F4C414C616F6Fllu, // lo_Laoo_LA
- 0xADCB43444C61746Ellu, // lol_Latn_CD
- 0xE5CB5A4D4C61746Ellu, // loz_Latn_ZM
- 0x8A2B495241726162llu, // lrc_Arab_IR
- 0x6C744C544C61746Ellu, // lt_Latn_LT
- 0x9A6B4C564C61746Ellu, // ltg_Latn_LV
- 0x6C7543444C61746Ellu, // lu_Latn_CD
- 0x828B43444C61746Ellu, // lua_Latn_CD
- 0xBA8B4B454C61746Ellu, // luo_Latn_KE
- 0xE28B4B454C61746Ellu, // luy_Latn_KE
- 0xE68B495241726162llu, // luz_Arab_IR
- 0x6C764C564C61746Ellu, // lv_Latn_LV
- 0xAECB544854686169llu, // lwl_Thai_TH
- 0x9F2B434E48616E73llu, // lzh_Hans_CN
- 0xE72B54524C61746Ellu, // lzz_Latn_TR
- 0x8C0C49444C61746Ellu, // mad_Latn_ID
- 0x940C434D4C61746Ellu, // maf_Latn_CM
- 0x980C494E44657661llu, // mag_Deva_IN
- 0xA00C494E44657661llu, // mai_Deva_IN
- 0xA80C49444C61746Ellu, // mak_Latn_ID
- 0xB40C474D4C61746Ellu, // man_Latn_GM
- 0xB40C474E4E6B6F6Fllu, // man_Nkoo_GN
- 0xC80C4B454C61746Ellu, // mas_Latn_KE
- 0xE40C4D584C61746Ellu, // maz_Latn_MX
- 0x946C52554379726Cllu, // mdf_Cyrl_RU
- 0x9C6C50484C61746Ellu, // mdh_Latn_PH
- 0xC46C49444C61746Ellu, // mdr_Latn_ID
- 0xB48C534C4C61746Ellu, // men_Latn_SL
- 0xC48C4B454C61746Ellu, // mer_Latn_KE
- 0x80AC544841726162llu, // mfa_Arab_TH
- 0x90AC4D554C61746Ellu, // mfe_Latn_MU
- 0x6D674D474C61746Ellu, // mg_Latn_MG
- 0x9CCC4D5A4C61746Ellu, // mgh_Latn_MZ
- 0xB8CC434D4C61746Ellu, // mgo_Latn_CM
- 0xBCCC4E5044657661llu, // mgp_Deva_NP
- 0xE0CC545A4C61746Ellu, // mgy_Latn_TZ
- 0x6D684D484C61746Ellu, // mh_Latn_MH
- 0x6D694E5A4C61746Ellu, // mi_Latn_NZ
- 0xB50C49444C61746Ellu, // min_Latn_ID
- 0xC90C495148617472llu, // mis_Hatr_IQ
- 0x6D6B4D4B4379726Cllu, // mk_Cyrl_MK
- 0x6D6C494E4D6C796Dllu, // ml_Mlym_IN
- 0xC96C53444C61746Ellu, // mls_Latn_SD
- 0x6D6E4D4E4379726Cllu, // mn_Cyrl_MN
- 0x6D6E434E4D6F6E67llu, // mn_Mong_CN
- 0xA1AC494E42656E67llu, // mni_Beng_IN
- 0xD9AC4D4D4D796D72llu, // mnw_Mymr_MM
- 0x91CC43414C61746Ellu, // moe_Latn_CA
- 0x9DCC43414C61746Ellu, // moh_Latn_CA
- 0xC9CC42464C61746Ellu, // mos_Latn_BF
- 0x6D72494E44657661llu, // mr_Deva_IN
- 0x8E2C4E5044657661llu, // mrd_Deva_NP
- 0xA62C52554379726Cllu, // mrj_Cyrl_RU
- 0xBA2C42444D726F6Fllu, // mro_Mroo_BD
- 0x6D734D594C61746Ellu, // ms_Latn_MY
- 0x6D744D544C61746Ellu, // mt_Latn_MT
- 0xC66C494E44657661llu, // mtr_Deva_IN
- 0x828C434D4C61746Ellu, // mua_Latn_CM
- 0xCA8C55534C61746Ellu, // mus_Latn_US
- 0xE2AC504B41726162llu, // mvy_Arab_PK
- 0xAACC4D4C4C61746Ellu, // mwk_Latn_ML
- 0xC6CC494E44657661llu, // mwr_Deva_IN
- 0xD6CC49444C61746Ellu, // mwv_Latn_ID
- 0x8AEC5A574C61746Ellu, // mxc_Latn_ZW
- 0x6D794D4D4D796D72llu, // my_Mymr_MM
- 0xD70C52554379726Cllu, // myv_Cyrl_RU
- 0xDF0C55474C61746Ellu, // myx_Latn_UG
- 0xE70C49524D616E64llu, // myz_Mand_IR
- 0xB72C495241726162llu, // mzn_Arab_IR
- 0x6E614E524C61746Ellu, // na_Latn_NR
- 0xB40D434E48616E73llu, // nan_Hans_CN
- 0xBC0D49544C61746Ellu, // nap_Latn_IT
- 0xC00D4E414C61746Ellu, // naq_Latn_NA
- 0x6E624E4F4C61746Ellu, // nb_Latn_NO
- 0x9C4D4D584C61746Ellu, // nch_Latn_MX
- 0x6E645A574C61746Ellu, // nd_Latn_ZW
- 0x886D4D5A4C61746Ellu, // ndc_Latn_MZ
- 0xC86D44454C61746Ellu, // nds_Latn_DE
- 0x6E654E5044657661llu, // ne_Deva_NP
- 0xD88D4E5044657661llu, // new_Deva_NP
- 0x6E674E414C61746Ellu, // ng_Latn_NA
- 0xACCD4D5A4C61746Ellu, // ngl_Latn_MZ
- 0x90ED4D584C61746Ellu, // nhe_Latn_MX
- 0xD8ED4D584C61746Ellu, // nhw_Latn_MX
- 0xA50D49444C61746Ellu, // nij_Latn_ID
- 0xD10D4E554C61746Ellu, // niu_Latn_NU
- 0xB92D494E4C61746Ellu, // njo_Latn_IN
- 0x6E6C4E4C4C61746Ellu, // nl_Latn_NL
- 0x998D434D4C61746Ellu, // nmg_Latn_CM
- 0x6E6E4E4F4C61746Ellu, // nn_Latn_NO
- 0x9DAD434D4C61746Ellu, // nnh_Latn_CM
- 0x6E6F4E4F4C61746Ellu, // no_Latn_NO
- 0x8DCD54484C616E61llu, // nod_Lana_TH
- 0x91CD494E44657661llu, // noe_Deva_IN
- 0xB5CD534552756E72llu, // non_Runr_SE
- 0xBA0D474E4E6B6F6Fllu, // nqo_Nkoo_GN
- 0x6E725A414C61746Ellu, // nr_Latn_ZA
- 0xAA4D434143616E73llu, // nsk_Cans_CA
- 0xBA4D5A414C61746Ellu, // nso_Latn_ZA
- 0xCA8D53534C61746Ellu, // nus_Latn_SS
- 0x6E7655534C61746Ellu, // nv_Latn_US
- 0xC2ED434E4C61746Ellu, // nxq_Latn_CN
- 0x6E794D574C61746Ellu, // ny_Latn_MW
- 0xB30D545A4C61746Ellu, // nym_Latn_TZ
- 0xB70D55474C61746Ellu, // nyn_Latn_UG
- 0xA32D47484C61746Ellu, // nzi_Latn_GH
- 0x6F6346524C61746Ellu, // oc_Latn_FR
- 0x6F6D45544C61746Ellu, // om_Latn_ET
- 0x6F72494E4F727961llu, // or_Orya_IN
- 0x6F7347454379726Cllu, // os_Cyrl_GE
- 0x824E55534F736765llu, // osa_Osge_US
- 0xAA6E4D4E4F726B68llu, // otk_Orkh_MN
- 0x7061504B41726162llu, // pa_Arab_PK
- 0x7061494E47757275llu, // pa_Guru_IN
- 0x980F50484C61746Ellu, // pag_Latn_PH
- 0xAC0F495250686C69llu, // pal_Phli_IR
- 0xAC0F434E50686C70llu, // pal_Phlp_CN
- 0xB00F50484C61746Ellu, // pam_Latn_PH
- 0xBC0F41574C61746Ellu, // pap_Latn_AW
- 0xD00F50574C61746Ellu, // pau_Latn_PW
- 0x8C4F46524C61746Ellu, // pcd_Latn_FR
- 0xB04F4E474C61746Ellu, // pcm_Latn_NG
- 0x886F55534C61746Ellu, // pdc_Latn_US
- 0xCC6F43414C61746Ellu, // pdt_Latn_CA
- 0xB88F49525870656Fllu, // peo_Xpeo_IR
- 0xACAF44454C61746Ellu, // pfl_Latn_DE
- 0xB4EF4C4250686E78llu, // phn_Phnx_LB
- 0x814F494E42726168llu, // pka_Brah_IN
- 0xB94F4B454C61746Ellu, // pko_Latn_KE
- 0x706C504C4C61746Ellu, // pl_Latn_PL
- 0xC98F49544C61746Ellu, // pms_Latn_IT
- 0xCDAF47524772656Bllu, // pnt_Grek_GR
- 0xB5CF464D4C61746Ellu, // pon_Latn_FM
- 0x822F504B4B686172llu, // pra_Khar_PK
- 0x8E2F495241726162llu, // prd_Arab_IR
- 0x7073414641726162llu, // ps_Arab_AF
- 0x707442524C61746Ellu, // pt_Latn_BR
- 0xD28F47414C61746Ellu, // puu_Latn_GA
- 0x717550454C61746Ellu, // qu_Latn_PE
- 0x8A9047544C61746Ellu, // quc_Latn_GT
- 0x9A9045434C61746Ellu, // qug_Latn_EC
- 0xA411494E44657661llu, // raj_Deva_IN
- 0x945152454C61746Ellu, // rcf_Latn_RE
- 0xA49149444C61746Ellu, // rej_Latn_ID
- 0xB4D149544C61746Ellu, // rgn_Latn_IT
- 0x8111494E4C61746Ellu, // ria_Latn_IN
- 0x95114D4154666E67llu, // rif_Tfng_MA
- 0xC9314E5044657661llu, // rjs_Deva_NP
- 0xCD51424442656E67llu, // rkt_Beng_BD
- 0x726D43484C61746Ellu, // rm_Latn_CH
- 0x959146494C61746Ellu, // rmf_Latn_FI
- 0xB99143484C61746Ellu, // rmo_Latn_CH
- 0xCD91495241726162llu, // rmt_Arab_IR
- 0xD19153454C61746Ellu, // rmu_Latn_SE
- 0x726E42494C61746Ellu, // rn_Latn_BI
- 0x99B14D5A4C61746Ellu, // rng_Latn_MZ
- 0x726F524F4C61746Ellu, // ro_Latn_RO
- 0x85D149444C61746Ellu, // rob_Latn_ID
- 0x95D1545A4C61746Ellu, // rof_Latn_TZ
- 0xB271464A4C61746Ellu, // rtm_Latn_FJ
- 0x727552554379726Cllu, // ru_Cyrl_RU
- 0x929155414379726Cllu, // rue_Cyrl_UA
- 0x9A9153424C61746Ellu, // rug_Latn_SB
- 0x727752574C61746Ellu, // rw_Latn_RW
- 0xAAD1545A4C61746Ellu, // rwk_Latn_TZ
- 0xD3114A504B616E61llu, // ryu_Kana_JP
- 0x7361494E44657661llu, // sa_Deva_IN
- 0x941247484C61746Ellu, // saf_Latn_GH
- 0x9C1252554379726Cllu, // sah_Cyrl_RU
- 0xC0124B454C61746Ellu, // saq_Latn_KE
- 0xC81249444C61746Ellu, // sas_Latn_ID
- 0xCC12494E4C61746Ellu, // sat_Latn_IN
- 0xE412494E53617572llu, // saz_Saur_IN
- 0xBC32545A4C61746Ellu, // sbp_Latn_TZ
- 0x736349544C61746Ellu, // sc_Latn_IT
- 0xA852494E44657661llu, // sck_Deva_IN
- 0xB45249544C61746Ellu, // scn_Latn_IT
- 0xB85247424C61746Ellu, // sco_Latn_GB
- 0xC85243414C61746Ellu, // scs_Latn_CA
- 0x7364504B41726162llu, // sd_Arab_PK
- 0x7364494E44657661llu, // sd_Deva_IN
- 0x7364494E4B686F6Allu, // sd_Khoj_IN
- 0x7364494E53696E64llu, // sd_Sind_IN
- 0x887249544C61746Ellu, // sdc_Latn_IT
- 0x9C72495241726162llu, // sdh_Arab_IR
- 0x73654E4F4C61746Ellu, // se_Latn_NO
- 0x949243494C61746Ellu, // sef_Latn_CI
- 0x9C924D5A4C61746Ellu, // seh_Latn_MZ
- 0xA0924D584C61746Ellu, // sei_Latn_MX
- 0xC8924D4C4C61746Ellu, // ses_Latn_ML
- 0x736743464C61746Ellu, // sg_Latn_CF
- 0x80D249454F67616Dllu, // sga_Ogam_IE
- 0xC8D24C544C61746Ellu, // sgs_Latn_LT
- 0xA0F24D4154666E67llu, // shi_Tfng_MA
- 0xB4F24D4D4D796D72llu, // shn_Mymr_MM
- 0x73694C4B53696E68llu, // si_Sinh_LK
- 0x8D1245544C61746Ellu, // sid_Latn_ET
- 0x736B534B4C61746Ellu, // sk_Latn_SK
- 0xC552504B41726162llu, // skr_Arab_PK
- 0x736C53494C61746Ellu, // sl_Latn_SI
- 0xA172504C4C61746Ellu, // sli_Latn_PL
- 0xE17249444C61746Ellu, // sly_Latn_ID
- 0x736D57534C61746Ellu, // sm_Latn_WS
- 0x819253454C61746Ellu, // sma_Latn_SE
- 0xA59253454C61746Ellu, // smj_Latn_SE
- 0xB59246494C61746Ellu, // smn_Latn_FI
- 0xBD92494C53616D72llu, // smp_Samr_IL
- 0xC99246494C61746Ellu, // sms_Latn_FI
- 0x736E5A574C61746Ellu, // sn_Latn_ZW
- 0xA9B24D4C4C61746Ellu, // snk_Latn_ML
- 0x736F534F4C61746Ellu, // so_Latn_SO
- 0xD1D2544854686169llu, // sou_Thai_TH
- 0x7371414C4C61746Ellu, // sq_Latn_AL
- 0x737252534379726Cllu, // sr_Cyrl_RS
- 0x737252534C61746Ellu, // sr_Latn_RS
- 0x8632494E536F7261llu, // srb_Sora_IN
- 0xB63253524C61746Ellu, // srn_Latn_SR
- 0xC632534E4C61746Ellu, // srr_Latn_SN
- 0xDE32494E44657661llu, // srx_Deva_IN
- 0x73735A414C61746Ellu, // ss_Latn_ZA
- 0xE25245524C61746Ellu, // ssy_Latn_ER
- 0x73745A414C61746Ellu, // st_Latn_ZA
- 0xC27244454C61746Ellu, // stq_Latn_DE
- 0x737549444C61746Ellu, // su_Latn_ID
- 0xAA92545A4C61746Ellu, // suk_Latn_TZ
- 0xCA92474E4C61746Ellu, // sus_Latn_GN
- 0x737653454C61746Ellu, // sv_Latn_SE
- 0x7377545A4C61746Ellu, // sw_Latn_TZ
- 0x86D2595441726162llu, // swb_Arab_YT
- 0x8AD243444C61746Ellu, // swc_Latn_CD
- 0x9AD244454C61746Ellu, // swg_Latn_DE
- 0xD6D2494E44657661llu, // swv_Deva_IN
- 0xB6F249444C61746Ellu, // sxn_Latn_ID
- 0xAF12424442656E67llu, // syl_Beng_BD
- 0xC712495153797263llu, // syr_Syrc_IQ
- 0xAF32504C4C61746Ellu, // szl_Latn_PL
- 0x7461494E54616D6Cllu, // ta_Taml_IN
- 0xA4134E5044657661llu, // taj_Deva_NP
- 0xD83350484C61746Ellu, // tbw_Latn_PH
- 0xE053494E4B6E6461llu, // tcy_Knda_IN
- 0x8C73434E54616C65llu, // tdd_Tale_CN
- 0x98734E5044657661llu, // tdg_Deva_NP
- 0x9C734E5044657661llu, // tdh_Deva_NP
- 0x7465494E54656C75llu, // te_Telu_IN
- 0xB093534C4C61746Ellu, // tem_Latn_SL
- 0xB89355474C61746Ellu, // teo_Latn_UG
- 0xCC93544C4C61746Ellu, // tet_Latn_TL
- 0x7467504B41726162llu, // tg_Arab_PK
- 0x7467544A4379726Cllu, // tg_Cyrl_TJ
- 0x7468544854686169llu, // th_Thai_TH
- 0xACF34E5044657661llu, // thl_Deva_NP
- 0xC0F34E5044657661llu, // thq_Deva_NP
- 0xC4F34E5044657661llu, // thr_Deva_NP
- 0x7469455445746869llu, // ti_Ethi_ET
- 0x9913455245746869llu, // tig_Ethi_ER
- 0xD5134E474C61746Ellu, // tiv_Latn_NG
- 0x746B544D4C61746Ellu, // tk_Latn_TM
- 0xAD53544B4C61746Ellu, // tkl_Latn_TK
- 0xC553415A4C61746Ellu, // tkr_Latn_AZ
- 0xCD534E5044657661llu, // tkt_Deva_NP
- 0x746C50484C61746Ellu, // tl_Latn_PH
- 0xE173415A4C61746Ellu, // tly_Latn_AZ
- 0x9D934E454C61746Ellu, // tmh_Latn_NE
- 0x746E5A414C61746Ellu, // tn_Latn_ZA
- 0x746F544F4C61746Ellu, // to_Latn_TO
- 0x99D34D574C61746Ellu, // tog_Latn_MW
- 0xA1F350474C61746Ellu, // tpi_Latn_PG
- 0x747254524C61746Ellu, // tr_Latn_TR
- 0xD23354524C61746Ellu, // tru_Latn_TR
- 0xD63354574C61746Ellu, // trv_Latn_TW
- 0x74735A414C61746Ellu, // ts_Latn_ZA
- 0x8E5347524772656Bllu, // tsd_Grek_GR
- 0x96534E5044657661llu, // tsf_Deva_NP
- 0x9A5350484C61746Ellu, // tsg_Latn_PH
- 0xA653425454696274llu, // tsj_Tibt_BT
- 0x747452554379726Cllu, // tt_Cyrl_RU
- 0xA67355474C61746Ellu, // ttj_Latn_UG
- 0xCA73544854686169llu, // tts_Thai_TH
- 0xCE73415A4C61746Ellu, // ttt_Latn_AZ
- 0xB2934D574C61746Ellu, // tum_Latn_MW
- 0xAEB354564C61746Ellu, // tvl_Latn_TV
- 0xC2D34E454C61746Ellu, // twq_Latn_NE
- 0x9AF3434E54616E67llu, // txg_Tang_CN
- 0x747950464C61746Ellu, // ty_Latn_PF
- 0xD71352554379726Cllu, // tyv_Cyrl_RU
- 0xB3334D414C61746Ellu, // tzm_Latn_MA
- 0xB07452554379726Cllu, // udm_Cyrl_RU
- 0x7567434E41726162llu, // ug_Arab_CN
- 0x75674B5A4379726Cllu, // ug_Cyrl_KZ
- 0x80D4535955676172llu, // uga_Ugar_SY
- 0x756B55414379726Cllu, // uk_Cyrl_UA
- 0xA174464D4C61746Ellu, // uli_Latn_FM
- 0x8594414F4C61746Ellu, // umb_Latn_AO
- 0xC5B4494E42656E67llu, // unr_Beng_IN
- 0xC5B44E5044657661llu, // unr_Deva_NP
- 0xDDB4494E42656E67llu, // unx_Beng_IN
- 0x7572504B41726162llu, // ur_Arab_PK
- 0x757A414641726162llu, // uz_Arab_AF
- 0x757A555A4C61746Ellu, // uz_Latn_UZ
- 0xA0154C5256616969llu, // vai_Vaii_LR
- 0x76655A414C61746Ellu, // ve_Latn_ZA
- 0x889549544C61746Ellu, // vec_Latn_IT
- 0xBC9552554C61746Ellu, // vep_Latn_RU
- 0x7669564E4C61746Ellu, // vi_Latn_VN
- 0x891553584C61746Ellu, // vic_Latn_SX
- 0xC97542454C61746Ellu, // vls_Latn_BE
- 0x959544454C61746Ellu, // vmf_Latn_DE
- 0xD9954D5A4C61746Ellu, // vmw_Latn_MZ
- 0xCDD552554C61746Ellu, // vot_Latn_RU
- 0xBA3545454C61746Ellu, // vro_Latn_EE
- 0xB695545A4C61746Ellu, // vun_Latn_TZ
- 0x776142454C61746Ellu, // wa_Latn_BE
- 0x901643484C61746Ellu, // wae_Latn_CH
- 0xAC16455445746869llu, // wal_Ethi_ET
- 0xC41650484C61746Ellu, // war_Latn_PH
- 0xBC3641554C61746Ellu, // wbp_Latn_AU
- 0xC036494E54656C75llu, // wbq_Telu_IN
- 0xC436494E44657661llu, // wbr_Deva_IN
- 0xC97657464C61746Ellu, // wls_Latn_WF
- 0xA1B64B4D41726162llu, // wni_Arab_KM
- 0x776F534E4C61746Ellu, // wo_Latn_SN
- 0xB276494E44657661llu, // wtm_Deva_IN
- 0xD296434E48616E73llu, // wuu_Hans_CN
- 0xD41742524C61746Ellu, // xav_Latn_BR
- 0xC457545243617269llu, // xcr_Cari_TR
- 0x78685A414C61746Ellu, // xh_Latn_ZA
- 0x897754524C796369llu, // xlc_Lyci_TR
- 0x8D7754524C796469llu, // xld_Lydi_TR
- 0x9597474547656F72llu, // xmf_Geor_GE
- 0xB597434E4D616E69llu, // xmn_Mani_CN
- 0xC59753444D657263llu, // xmr_Merc_SD
- 0x81B753414E617262llu, // xna_Narb_SA
- 0xC5B7494E44657661llu, // xnr_Deva_IN
- 0x99D755474C61746Ellu, // xog_Latn_UG
- 0xC5F7495250727469llu, // xpr_Prti_IR
- 0x8257594553617262llu, // xsa_Sarb_YE
- 0xC6574E5044657661llu, // xsr_Deva_NP
- 0xB8184D5A4C61746Ellu, // yao_Latn_MZ
- 0xBC18464D4C61746Ellu, // yap_Latn_FM
- 0xD418434D4C61746Ellu, // yav_Latn_CM
- 0x8438434D4C61746Ellu, // ybb_Latn_CM
- 0x796F4E474C61746Ellu, // yo_Latn_NG
- 0xAE3842524C61746Ellu, // yrl_Latn_BR
- 0x82984D584C61746Ellu, // yua_Latn_MX
- 0x9298434E48616E73llu, // yue_Hans_CN
- 0x9298484B48616E74llu, // yue_Hant_HK
- 0x7A61434E4C61746Ellu, // za_Latn_CN
- 0x981953444C61746Ellu, // zag_Latn_SD
- 0xA4794B4D41726162llu, // zdj_Arab_KM
- 0x80994E4C4C61746Ellu, // zea_Latn_NL
- 0x9CD94D4154666E67llu, // zgh_Tfng_MA
- 0x7A685457426F706Fllu, // zh_Bopo_TW
- 0x7A68545748616E62llu, // zh_Hanb_TW
- 0x7A68434E48616E73llu, // zh_Hans_CN
- 0x7A68545748616E74llu, // zh_Hant_TW
- 0xB17954474C61746Ellu, // zlm_Latn_TG
- 0xA1994D594C61746Ellu, // zmi_Latn_MY
- 0x7A755A414C61746Ellu, // zu_Latn_ZA
- 0x833954524C61746Ellu, // zza_Latn_TR
+ 0x616145544C61746ELLU, // aa_Latn_ET
+ 0x616247454379726CLLU, // ab_Cyrl_GE
+ 0xC42047484C61746ELLU, // abr_Latn_GH
+ 0x904049444C61746ELLU, // ace_Latn_ID
+ 0x9C4055474C61746ELLU, // ach_Latn_UG
+ 0x806047484C61746ELLU, // ada_Latn_GH
+ 0xE06052554379726CLLU, // ady_Cyrl_RU
+ 0x6165495241767374LLU, // ae_Avst_IR
+ 0x8480544E41726162LLU, // aeb_Arab_TN
+ 0x61665A414C61746ELLU, // af_Latn_ZA
+ 0xC0C0434D4C61746ELLU, // agq_Latn_CM
+ 0xB8E0494E41686F6DLLU, // aho_Ahom_IN
+ 0x616B47484C61746ELLU, // ak_Latn_GH
+ 0xA940495158737578LLU, // akk_Xsux_IQ
+ 0xB560584B4C61746ELLU, // aln_Latn_XK
+ 0xCD6052554379726CLLU, // alt_Cyrl_RU
+ 0x616D455445746869LLU, // am_Ethi_ET
+ 0xB9804E474C61746ELLU, // amo_Latn_NG
+ 0xE5C049444C61746ELLU, // aoz_Latn_ID
+ 0x8DE0544741726162LLU, // apd_Arab_TG
+ 0x6172454741726162LLU, // ar_Arab_EG
+ 0x8A20495241726D69LLU, // arc_Armi_IR
+ 0x8A204A4F4E626174LLU, // arc_Nbat_JO
+ 0x8A20535950616C6DLLU, // arc_Palm_SY
+ 0xB620434C4C61746ELLU, // arn_Latn_CL
+ 0xBA20424F4C61746ELLU, // aro_Latn_BO
+ 0xC220445A41726162LLU, // arq_Arab_DZ
+ 0xE2204D4141726162LLU, // ary_Arab_MA
+ 0xE620454741726162LLU, // arz_Arab_EG
+ 0x6173494E42656E67LLU, // as_Beng_IN
+ 0x8240545A4C61746ELLU, // asa_Latn_TZ
+ 0x9240555353676E77LLU, // ase_Sgnw_US
+ 0xCE4045534C61746ELLU, // ast_Latn_ES
+ 0xA66043414C61746ELLU, // atj_Latn_CA
+ 0x617652554379726CLLU, // av_Cyrl_RU
+ 0x82C0494E44657661LLU, // awa_Deva_IN
+ 0x6179424F4C61746ELLU, // ay_Latn_BO
+ 0x617A495241726162LLU, // az_Arab_IR
+ 0x617A415A4C61746ELLU, // az_Latn_AZ
+ 0x626152554379726CLLU, // ba_Cyrl_RU
+ 0xAC01504B41726162LLU, // bal_Arab_PK
+ 0xB40149444C61746ELLU, // ban_Latn_ID
+ 0xBC014E5044657661LLU, // bap_Deva_NP
+ 0xC40141544C61746ELLU, // bar_Latn_AT
+ 0xC801434D4C61746ELLU, // bas_Latn_CM
+ 0xDC01434D42616D75LLU, // bax_Bamu_CM
+ 0x882149444C61746ELLU, // bbc_Latn_ID
+ 0xA421434D4C61746ELLU, // bbj_Latn_CM
+ 0xA04143494C61746ELLU, // bci_Latn_CI
+ 0x626542594379726CLLU, // be_Cyrl_BY
+ 0xA481534441726162LLU, // bej_Arab_SD
+ 0xB0815A4D4C61746ELLU, // bem_Latn_ZM
+ 0xD88149444C61746ELLU, // bew_Latn_ID
+ 0xE481545A4C61746ELLU, // bez_Latn_TZ
+ 0x8CA1434D4C61746ELLU, // bfd_Latn_CM
+ 0xC0A1494E54616D6CLLU, // bfq_Taml_IN
+ 0xCCA1504B41726162LLU, // bft_Arab_PK
+ 0xE0A1494E44657661LLU, // bfy_Deva_IN
+ 0x626742474379726CLLU, // bg_Cyrl_BG
+ 0x88C1494E44657661LLU, // bgc_Deva_IN
+ 0xB4C1504B41726162LLU, // bgn_Arab_PK
+ 0xDCC154524772656BLLU, // bgx_Grek_TR
+ 0x84E1494E44657661LLU, // bhb_Deva_IN
+ 0xA0E1494E44657661LLU, // bhi_Deva_IN
+ 0xA8E150484C61746ELLU, // bhk_Latn_PH
+ 0xB8E1494E44657661LLU, // bho_Deva_IN
+ 0x626956554C61746ELLU, // bi_Latn_VU
+ 0xA90150484C61746ELLU, // bik_Latn_PH
+ 0xB5014E474C61746ELLU, // bin_Latn_NG
+ 0xA521494E44657661LLU, // bjj_Deva_IN
+ 0xB52149444C61746ELLU, // bjn_Latn_ID
+ 0xB141434D4C61746ELLU, // bkm_Latn_CM
+ 0xD14150484C61746ELLU, // bku_Latn_PH
+ 0xCD61564E54617674LLU, // blt_Tavt_VN
+ 0x626D4D4C4C61746ELLU, // bm_Latn_ML
+ 0xC1814D4C4C61746ELLU, // bmq_Latn_ML
+ 0x626E424442656E67LLU, // bn_Beng_BD
+ 0x626F434E54696274LLU, // bo_Tibt_CN
+ 0xE1E1494E42656E67LLU, // bpy_Beng_IN
+ 0xA201495241726162LLU, // bqi_Arab_IR
+ 0xD60143494C61746ELLU, // bqv_Latn_CI
+ 0x627246524C61746ELLU, // br_Latn_FR
+ 0x8221494E44657661LLU, // bra_Deva_IN
+ 0x9E21504B41726162LLU, // brh_Arab_PK
+ 0xDE21494E44657661LLU, // brx_Deva_IN
+ 0x627342414C61746ELLU, // bs_Latn_BA
+ 0xC2414C5242617373LLU, // bsq_Bass_LR
+ 0xCA41434D4C61746ELLU, // bss_Latn_CM
+ 0xBA6150484C61746ELLU, // bto_Latn_PH
+ 0xD661504B44657661LLU, // btv_Deva_PK
+ 0x828152554379726CLLU, // bua_Cyrl_RU
+ 0x8A8159544C61746ELLU, // buc_Latn_YT
+ 0x9A8149444C61746ELLU, // bug_Latn_ID
+ 0xB281434D4C61746ELLU, // bum_Latn_CM
+ 0x86A147514C61746ELLU, // bvb_Latn_GQ
+ 0xB701455245746869LLU, // byn_Ethi_ER
+ 0xD701434D4C61746ELLU, // byv_Latn_CM
+ 0x93214D4C4C61746ELLU, // bze_Latn_ML
+ 0x636145534C61746ELLU, // ca_Latn_ES
+ 0x9C424E474C61746ELLU, // cch_Latn_NG
+ 0xBC42494E42656E67LLU, // ccp_Beng_IN
+ 0xBC42424443616B6DLLU, // ccp_Cakm_BD
+ 0x636552554379726CLLU, // ce_Cyrl_RU
+ 0x848250484C61746ELLU, // ceb_Latn_PH
+ 0x98C255474C61746ELLU, // cgg_Latn_UG
+ 0x636847554C61746ELLU, // ch_Latn_GU
+ 0xA8E2464D4C61746ELLU, // chk_Latn_FM
+ 0xB0E252554379726CLLU, // chm_Cyrl_RU
+ 0xB8E255534C61746ELLU, // cho_Latn_US
+ 0xBCE243414C61746ELLU, // chp_Latn_CA
+ 0xC4E2555343686572LLU, // chr_Cher_US
+ 0x81224B4841726162LLU, // cja_Arab_KH
+ 0xB122564E4368616DLLU, // cjm_Cham_VN
+ 0x8542495141726162LLU, // ckb_Arab_IQ
+ 0x636F46524C61746ELLU, // co_Latn_FR
+ 0xBDC24547436F7074LLU, // cop_Copt_EG
+ 0xC9E250484C61746ELLU, // cps_Latn_PH
+ 0x6372434143616E73LLU, // cr_Cans_CA
+ 0xA622434143616E73LLU, // crj_Cans_CA
+ 0xAA22434143616E73LLU, // crk_Cans_CA
+ 0xAE22434143616E73LLU, // crl_Cans_CA
+ 0xB222434143616E73LLU, // crm_Cans_CA
+ 0xCA2253434C61746ELLU, // crs_Latn_SC
+ 0x6373435A4C61746ELLU, // cs_Latn_CZ
+ 0x8642504C4C61746ELLU, // csb_Latn_PL
+ 0xDA42434143616E73LLU, // csw_Cans_CA
+ 0x8E624D4D50617563LLU, // ctd_Pauc_MM
+ 0x637552554379726CLLU, // cu_Cyrl_RU
+ 0x63754247476C6167LLU, // cu_Glag_BG
+ 0x637652554379726CLLU, // cv_Cyrl_RU
+ 0x637947424C61746ELLU, // cy_Latn_GB
+ 0x6461444B4C61746ELLU, // da_Latn_DK
+ 0xA80355534C61746ELLU, // dak_Latn_US
+ 0xC40352554379726CLLU, // dar_Cyrl_RU
+ 0xD4034B454C61746ELLU, // dav_Latn_KE
+ 0x8843494E41726162LLU, // dcc_Arab_IN
+ 0x646544454C61746ELLU, // de_Latn_DE
+ 0xB48343414C61746ELLU, // den_Latn_CA
+ 0xC4C343414C61746ELLU, // dgr_Latn_CA
+ 0x91234E454C61746ELLU, // dje_Latn_NE
+ 0xA5A343494C61746ELLU, // dnj_Latn_CI
+ 0xA1C3494E41726162LLU, // doi_Arab_IN
+ 0x864344454C61746ELLU, // dsb_Latn_DE
+ 0xB2634D4C4C61746ELLU, // dtm_Latn_ML
+ 0xBE634D594C61746ELLU, // dtp_Latn_MY
+ 0xE2634E5044657661LLU, // dty_Deva_NP
+ 0x8283434D4C61746ELLU, // dua_Latn_CM
+ 0x64764D5654686161LLU, // dv_Thaa_MV
+ 0xBB03534E4C61746ELLU, // dyo_Latn_SN
+ 0xD30342464C61746ELLU, // dyu_Latn_BF
+ 0x647A425454696274LLU, // dz_Tibt_BT
+ 0xD0244B454C61746ELLU, // ebu_Latn_KE
+ 0x656547484C61746ELLU, // ee_Latn_GH
+ 0xA0A44E474C61746ELLU, // efi_Latn_NG
+ 0xACC449544C61746ELLU, // egl_Latn_IT
+ 0xE0C4454745677970LLU, // egy_Egyp_EG
+ 0xE1444D4D4B616C69LLU, // eky_Kali_MM
+ 0x656C47524772656BLLU, // el_Grek_GR
+ 0x656E47424C61746ELLU, // en_Latn_GB
+ 0x656E55534C61746ELLU, // en_Latn_US
+ 0x656E474253686177LLU, // en_Shaw_GB
+ 0x657345534C61746ELLU, // es_Latn_ES
+ 0x65734D584C61746ELLU, // es_Latn_MX
+ 0x657355534C61746ELLU, // es_Latn_US
+ 0xD24455534C61746ELLU, // esu_Latn_US
+ 0x657445454C61746ELLU, // et_Latn_EE
+ 0xCE6449544974616CLLU, // ett_Ital_IT
+ 0x657545534C61746ELLU, // eu_Latn_ES
+ 0xBAC4434D4C61746ELLU, // ewo_Latn_CM
+ 0xCEE445534C61746ELLU, // ext_Latn_ES
+ 0x6661495241726162LLU, // fa_Arab_IR
+ 0xB40547514C61746ELLU, // fan_Latn_GQ
+ 0x6666474E41646C6DLLU, // ff_Adlm_GN
+ 0x6666534E4C61746ELLU, // ff_Latn_SN
+ 0xB0A54D4C4C61746ELLU, // ffm_Latn_ML
+ 0x666946494C61746ELLU, // fi_Latn_FI
+ 0x8105534441726162LLU, // fia_Arab_SD
+ 0xAD0550484C61746ELLU, // fil_Latn_PH
+ 0xCD0553454C61746ELLU, // fit_Latn_SE
+ 0x666A464A4C61746ELLU, // fj_Latn_FJ
+ 0x666F464F4C61746ELLU, // fo_Latn_FO
+ 0xB5C5424A4C61746ELLU, // fon_Latn_BJ
+ 0x667246524C61746ELLU, // fr_Latn_FR
+ 0x8A2555534C61746ELLU, // frc_Latn_US
+ 0xBE2546524C61746ELLU, // frp_Latn_FR
+ 0xC62544454C61746ELLU, // frr_Latn_DE
+ 0xCA2544454C61746ELLU, // frs_Latn_DE
+ 0x8685434D41726162LLU, // fub_Arab_CM
+ 0x8E8557464C61746ELLU, // fud_Latn_WF
+ 0x9685474E4C61746ELLU, // fuf_Latn_GN
+ 0xC2854E454C61746ELLU, // fuq_Latn_NE
+ 0xC68549544C61746ELLU, // fur_Latn_IT
+ 0xD6854E474C61746ELLU, // fuv_Latn_NG
+ 0xC6A553444C61746ELLU, // fvr_Latn_SD
+ 0x66794E4C4C61746ELLU, // fy_Latn_NL
+ 0x676149454C61746ELLU, // ga_Latn_IE
+ 0x800647484C61746ELLU, // gaa_Latn_GH
+ 0x98064D444C61746ELLU, // gag_Latn_MD
+ 0xB406434E48616E73LLU, // gan_Hans_CN
+ 0xE00649444C61746ELLU, // gay_Latn_ID
+ 0xB026494E44657661LLU, // gbm_Deva_IN
+ 0xE426495241726162LLU, // gbz_Arab_IR
+ 0xC44647464C61746ELLU, // gcr_Latn_GF
+ 0x676447424C61746ELLU, // gd_Latn_GB
+ 0xE486455445746869LLU, // gez_Ethi_ET
+ 0xB4C64E5044657661LLU, // ggn_Deva_NP
+ 0xAD064B494C61746ELLU, // gil_Latn_KI
+ 0xA926504B41726162LLU, // gjk_Arab_PK
+ 0xD126504B41726162LLU, // gju_Arab_PK
+ 0x676C45534C61746ELLU, // gl_Latn_ES
+ 0xA966495241726162LLU, // glk_Arab_IR
+ 0x676E50594C61746ELLU, // gn_Latn_PY
+ 0xB1C6494E44657661LLU, // gom_Deva_IN
+ 0xB5C6494E54656C75LLU, // gon_Telu_IN
+ 0xC5C649444C61746ELLU, // gor_Latn_ID
+ 0xC9C64E4C4C61746ELLU, // gos_Latn_NL
+ 0xCDC65541476F7468LLU, // got_Goth_UA
+ 0x8A26435943707274LLU, // grc_Cprt_CY
+ 0x8A2647524C696E62LLU, // grc_Linb_GR
+ 0xCE26494E42656E67LLU, // grt_Beng_IN
+ 0xDA4643484C61746ELLU, // gsw_Latn_CH
+ 0x6775494E47756A72LLU, // gu_Gujr_IN
+ 0x868642524C61746ELLU, // gub_Latn_BR
+ 0x8A86434F4C61746ELLU, // guc_Latn_CO
+ 0xC68647484C61746ELLU, // gur_Latn_GH
+ 0xE6864B454C61746ELLU, // guz_Latn_KE
+ 0x6776494D4C61746ELLU, // gv_Latn_IM
+ 0xC6A64E5044657661LLU, // gvr_Deva_NP
+ 0xA2C643414C61746ELLU, // gwi_Latn_CA
+ 0x68614E474C61746ELLU, // ha_Latn_NG
+ 0xA807434E48616E73LLU, // hak_Hans_CN
+ 0xD80755534C61746ELLU, // haw_Latn_US
+ 0xE407414641726162LLU, // haz_Arab_AF
+ 0x6865494C48656272LLU, // he_Hebr_IL
+ 0x6869494E44657661LLU, // hi_Deva_IN
+ 0x9507464A4C61746ELLU, // hif_Latn_FJ
+ 0xAD0750484C61746ELLU, // hil_Latn_PH
+ 0xD1675452486C7577LLU, // hlu_Hluw_TR
+ 0x8D87434E506C7264LLU, // hmd_Plrd_CN
+ 0x8DA7504B41726162LLU, // hnd_Arab_PK
+ 0x91A7494E44657661LLU, // hne_Deva_IN
+ 0xA5A74C41486D6E67LLU, // hnj_Hmng_LA
+ 0xB5A750484C61746ELLU, // hnn_Latn_PH
+ 0xB9A7504B41726162LLU, // hno_Arab_PK
+ 0x686F50474C61746ELLU, // ho_Latn_PG
+ 0x89C7494E44657661LLU, // hoc_Deva_IN
+ 0xA5C7494E44657661LLU, // hoj_Deva_IN
+ 0x687248524C61746ELLU, // hr_Latn_HR
+ 0x864744454C61746ELLU, // hsb_Latn_DE
+ 0xB647434E48616E73LLU, // hsn_Hans_CN
+ 0x687448544C61746ELLU, // ht_Latn_HT
+ 0x687548554C61746ELLU, // hu_Latn_HU
+ 0x6879414D41726D6ELLU, // hy_Armn_AM
+ 0x687A4E414C61746ELLU, // hz_Latn_NA
+ 0x696146524C61746ELLU, // ia_Latn_FR
+ 0x80284D594C61746ELLU, // iba_Latn_MY
+ 0x84284E474C61746ELLU, // ibb_Latn_NG
+ 0x696449444C61746ELLU, // id_Latn_ID
+ 0x69674E474C61746ELLU, // ig_Latn_NG
+ 0x6969434E59696969LLU, // ii_Yiii_CN
+ 0x696B55534C61746ELLU, // ik_Latn_US
+ 0xCD4843414C61746ELLU, // ikt_Latn_CA
+ 0xB96850484C61746ELLU, // ilo_Latn_PH
+ 0x696E49444C61746ELLU, // in_Latn_ID
+ 0x9DA852554379726CLLU, // inh_Cyrl_RU
+ 0x697349534C61746ELLU, // is_Latn_IS
+ 0x697449544C61746ELLU, // it_Latn_IT
+ 0x6975434143616E73LLU, // iu_Cans_CA
+ 0x6977494C48656272LLU, // iw_Hebr_IL
+ 0x9F2852554C61746ELLU, // izh_Latn_RU
+ 0x6A614A504A70616ELLU, // ja_Jpan_JP
+ 0xB0094A4D4C61746ELLU, // jam_Latn_JM
+ 0xB8C9434D4C61746ELLU, // jgo_Latn_CM
+ 0x8989545A4C61746ELLU, // jmc_Latn_TZ
+ 0xAD894E5044657661LLU, // jml_Deva_NP
+ 0xCE89444B4C61746ELLU, // jut_Latn_DK
+ 0x6A7649444C61746ELLU, // jv_Latn_ID
+ 0x6A7749444C61746ELLU, // jw_Latn_ID
+ 0x6B61474547656F72LLU, // ka_Geor_GE
+ 0x800A555A4379726CLLU, // kaa_Cyrl_UZ
+ 0x840A445A4C61746ELLU, // kab_Latn_DZ
+ 0x880A4D4D4C61746ELLU, // kac_Latn_MM
+ 0xA40A4E474C61746ELLU, // kaj_Latn_NG
+ 0xB00A4B454C61746ELLU, // kam_Latn_KE
+ 0xB80A4D4C4C61746ELLU, // kao_Latn_ML
+ 0x8C2A52554379726CLLU, // kbd_Cyrl_RU
+ 0xE02A4E4541726162LLU, // kby_Arab_NE
+ 0x984A4E474C61746ELLU, // kcg_Latn_NG
+ 0xA84A5A574C61746ELLU, // kck_Latn_ZW
+ 0x906A545A4C61746ELLU, // kde_Latn_TZ
+ 0x9C6A544741726162LLU, // kdh_Arab_TG
+ 0xCC6A544854686169LLU, // kdt_Thai_TH
+ 0x808A43564C61746ELLU, // kea_Latn_CV
+ 0xB48A434D4C61746ELLU, // ken_Latn_CM
+ 0xB8AA43494C61746ELLU, // kfo_Latn_CI
+ 0xC4AA494E44657661LLU, // kfr_Deva_IN
+ 0xE0AA494E44657661LLU, // kfy_Deva_IN
+ 0x6B6743444C61746ELLU, // kg_Latn_CD
+ 0x90CA49444C61746ELLU, // kge_Latn_ID
+ 0xBCCA42524C61746ELLU, // kgp_Latn_BR
+ 0x80EA494E4C61746ELLU, // kha_Latn_IN
+ 0x84EA434E54616C75LLU, // khb_Talu_CN
+ 0xB4EA494E44657661LLU, // khn_Deva_IN
+ 0xC0EA4D4C4C61746ELLU, // khq_Latn_ML
+ 0xCCEA494E4D796D72LLU, // kht_Mymr_IN
+ 0xD8EA504B41726162LLU, // khw_Arab_PK
+ 0x6B694B454C61746ELLU, // ki_Latn_KE
+ 0xD10A54524C61746ELLU, // kiu_Latn_TR
+ 0x6B6A4E414C61746ELLU, // kj_Latn_NA
+ 0x992A4C414C616F6FLLU, // kjg_Laoo_LA
+ 0x6B6B434E41726162LLU, // kk_Arab_CN
+ 0x6B6B4B5A4379726CLLU, // kk_Cyrl_KZ
+ 0xA54A434D4C61746ELLU, // kkj_Latn_CM
+ 0x6B6C474C4C61746ELLU, // kl_Latn_GL
+ 0xB56A4B454C61746ELLU, // kln_Latn_KE
+ 0x6B6D4B484B686D72LLU, // km_Khmr_KH
+ 0x858A414F4C61746ELLU, // kmb_Latn_AO
+ 0x6B6E494E4B6E6461LLU, // kn_Knda_IN
+ 0x6B6F4B524B6F7265LLU, // ko_Kore_KR
+ 0xA1CA52554379726CLLU, // koi_Cyrl_RU
+ 0xA9CA494E44657661LLU, // kok_Deva_IN
+ 0xC9CA464D4C61746ELLU, // kos_Latn_FM
+ 0x91EA4C524C61746ELLU, // kpe_Latn_LR
+ 0x8A2A52554379726CLLU, // krc_Cyrl_RU
+ 0xA22A534C4C61746ELLU, // kri_Latn_SL
+ 0xA62A50484C61746ELLU, // krj_Latn_PH
+ 0xAE2A52554C61746ELLU, // krl_Latn_RU
+ 0xD22A494E44657661LLU, // kru_Deva_IN
+ 0x6B73494E41726162LLU, // ks_Arab_IN
+ 0x864A545A4C61746ELLU, // ksb_Latn_TZ
+ 0x964A434D4C61746ELLU, // ksf_Latn_CM
+ 0x9E4A44454C61746ELLU, // ksh_Latn_DE
+ 0x6B75495141726162LLU, // ku_Arab_IQ
+ 0x6B7554524C61746ELLU, // ku_Latn_TR
+ 0xB28A52554379726CLLU, // kum_Cyrl_RU
+ 0x6B7652554379726CLLU, // kv_Cyrl_RU
+ 0xC6AA49444C61746ELLU, // kvr_Latn_ID
+ 0xDEAA504B41726162LLU, // kvx_Arab_PK
+ 0x6B7747424C61746ELLU, // kw_Latn_GB
+ 0xB2EA544854686169LLU, // kxm_Thai_TH
+ 0xBEEA504B41726162LLU, // kxp_Arab_PK
+ 0x6B79434E41726162LLU, // ky_Arab_CN
+ 0x6B794B474379726CLLU, // ky_Cyrl_KG
+ 0x6B7954524C61746ELLU, // ky_Latn_TR
+ 0x6C6156414C61746ELLU, // la_Latn_VA
+ 0x840B47524C696E61LLU, // lab_Lina_GR
+ 0x8C0B494C48656272LLU, // lad_Hebr_IL
+ 0x980B545A4C61746ELLU, // lag_Latn_TZ
+ 0x9C0B504B41726162LLU, // lah_Arab_PK
+ 0xA40B55474C61746ELLU, // laj_Latn_UG
+ 0x6C624C554C61746ELLU, // lb_Latn_LU
+ 0x902B52554379726CLLU, // lbe_Cyrl_RU
+ 0xD82B49444C61746ELLU, // lbw_Latn_ID
+ 0xBC4B434E54686169LLU, // lcp_Thai_CN
+ 0xBC8B494E4C657063LLU, // lep_Lepc_IN
+ 0xE48B52554379726CLLU, // lez_Cyrl_RU
+ 0x6C6755474C61746ELLU, // lg_Latn_UG
+ 0x6C694E4C4C61746ELLU, // li_Latn_NL
+ 0x950B4E5044657661LLU, // lif_Deva_NP
+ 0x950B494E4C696D62LLU, // lif_Limb_IN
+ 0xA50B49544C61746ELLU, // lij_Latn_IT
+ 0xC90B434E4C697375LLU, // lis_Lisu_CN
+ 0xBD2B49444C61746ELLU, // ljp_Latn_ID
+ 0xA14B495241726162LLU, // lki_Arab_IR
+ 0xCD4B55534C61746ELLU, // lkt_Latn_US
+ 0xB58B494E54656C75LLU, // lmn_Telu_IN
+ 0xB98B49544C61746ELLU, // lmo_Latn_IT
+ 0x6C6E43444C61746ELLU, // ln_Latn_CD
+ 0x6C6F4C414C616F6FLLU, // lo_Laoo_LA
+ 0xADCB43444C61746ELLU, // lol_Latn_CD
+ 0xE5CB5A4D4C61746ELLU, // loz_Latn_ZM
+ 0x8A2B495241726162LLU, // lrc_Arab_IR
+ 0x6C744C544C61746ELLU, // lt_Latn_LT
+ 0x9A6B4C564C61746ELLU, // ltg_Latn_LV
+ 0x6C7543444C61746ELLU, // lu_Latn_CD
+ 0x828B43444C61746ELLU, // lua_Latn_CD
+ 0xBA8B4B454C61746ELLU, // luo_Latn_KE
+ 0xE28B4B454C61746ELLU, // luy_Latn_KE
+ 0xE68B495241726162LLU, // luz_Arab_IR
+ 0x6C764C564C61746ELLU, // lv_Latn_LV
+ 0xAECB544854686169LLU, // lwl_Thai_TH
+ 0x9F2B434E48616E73LLU, // lzh_Hans_CN
+ 0xE72B54524C61746ELLU, // lzz_Latn_TR
+ 0x8C0C49444C61746ELLU, // mad_Latn_ID
+ 0x940C434D4C61746ELLU, // maf_Latn_CM
+ 0x980C494E44657661LLU, // mag_Deva_IN
+ 0xA00C494E44657661LLU, // mai_Deva_IN
+ 0xA80C49444C61746ELLU, // mak_Latn_ID
+ 0xB40C474D4C61746ELLU, // man_Latn_GM
+ 0xB40C474E4E6B6F6FLLU, // man_Nkoo_GN
+ 0xC80C4B454C61746ELLU, // mas_Latn_KE
+ 0xE40C4D584C61746ELLU, // maz_Latn_MX
+ 0x946C52554379726CLLU, // mdf_Cyrl_RU
+ 0x9C6C50484C61746ELLU, // mdh_Latn_PH
+ 0xC46C49444C61746ELLU, // mdr_Latn_ID
+ 0xB48C534C4C61746ELLU, // men_Latn_SL
+ 0xC48C4B454C61746ELLU, // mer_Latn_KE
+ 0x80AC544841726162LLU, // mfa_Arab_TH
+ 0x90AC4D554C61746ELLU, // mfe_Latn_MU
+ 0x6D674D474C61746ELLU, // mg_Latn_MG
+ 0x9CCC4D5A4C61746ELLU, // mgh_Latn_MZ
+ 0xB8CC434D4C61746ELLU, // mgo_Latn_CM
+ 0xBCCC4E5044657661LLU, // mgp_Deva_NP
+ 0xE0CC545A4C61746ELLU, // mgy_Latn_TZ
+ 0x6D684D484C61746ELLU, // mh_Latn_MH
+ 0x6D694E5A4C61746ELLU, // mi_Latn_NZ
+ 0xB50C49444C61746ELLU, // min_Latn_ID
+ 0xC90C495148617472LLU, // mis_Hatr_IQ
+ 0x6D6B4D4B4379726CLLU, // mk_Cyrl_MK
+ 0x6D6C494E4D6C796DLLU, // ml_Mlym_IN
+ 0xC96C53444C61746ELLU, // mls_Latn_SD
+ 0x6D6E4D4E4379726CLLU, // mn_Cyrl_MN
+ 0x6D6E434E4D6F6E67LLU, // mn_Mong_CN
+ 0xA1AC494E42656E67LLU, // mni_Beng_IN
+ 0xD9AC4D4D4D796D72LLU, // mnw_Mymr_MM
+ 0x91CC43414C61746ELLU, // moe_Latn_CA
+ 0x9DCC43414C61746ELLU, // moh_Latn_CA
+ 0xC9CC42464C61746ELLU, // mos_Latn_BF
+ 0x6D72494E44657661LLU, // mr_Deva_IN
+ 0x8E2C4E5044657661LLU, // mrd_Deva_NP
+ 0xA62C52554379726CLLU, // mrj_Cyrl_RU
+ 0xBA2C42444D726F6FLLU, // mro_Mroo_BD
+ 0x6D734D594C61746ELLU, // ms_Latn_MY
+ 0x6D744D544C61746ELLU, // mt_Latn_MT
+ 0xC66C494E44657661LLU, // mtr_Deva_IN
+ 0x828C434D4C61746ELLU, // mua_Latn_CM
+ 0xCA8C55534C61746ELLU, // mus_Latn_US
+ 0xE2AC504B41726162LLU, // mvy_Arab_PK
+ 0xAACC4D4C4C61746ELLU, // mwk_Latn_ML
+ 0xC6CC494E44657661LLU, // mwr_Deva_IN
+ 0xD6CC49444C61746ELLU, // mwv_Latn_ID
+ 0x8AEC5A574C61746ELLU, // mxc_Latn_ZW
+ 0x6D794D4D4D796D72LLU, // my_Mymr_MM
+ 0xD70C52554379726CLLU, // myv_Cyrl_RU
+ 0xDF0C55474C61746ELLU, // myx_Latn_UG
+ 0xE70C49524D616E64LLU, // myz_Mand_IR
+ 0xB72C495241726162LLU, // mzn_Arab_IR
+ 0x6E614E524C61746ELLU, // na_Latn_NR
+ 0xB40D434E48616E73LLU, // nan_Hans_CN
+ 0xBC0D49544C61746ELLU, // nap_Latn_IT
+ 0xC00D4E414C61746ELLU, // naq_Latn_NA
+ 0x6E624E4F4C61746ELLU, // nb_Latn_NO
+ 0x9C4D4D584C61746ELLU, // nch_Latn_MX
+ 0x6E645A574C61746ELLU, // nd_Latn_ZW
+ 0x886D4D5A4C61746ELLU, // ndc_Latn_MZ
+ 0xC86D44454C61746ELLU, // nds_Latn_DE
+ 0x6E654E5044657661LLU, // ne_Deva_NP
+ 0xD88D4E5044657661LLU, // new_Deva_NP
+ 0x6E674E414C61746ELLU, // ng_Latn_NA
+ 0xACCD4D5A4C61746ELLU, // ngl_Latn_MZ
+ 0x90ED4D584C61746ELLU, // nhe_Latn_MX
+ 0xD8ED4D584C61746ELLU, // nhw_Latn_MX
+ 0xA50D49444C61746ELLU, // nij_Latn_ID
+ 0xD10D4E554C61746ELLU, // niu_Latn_NU
+ 0xB92D494E4C61746ELLU, // njo_Latn_IN
+ 0x6E6C4E4C4C61746ELLU, // nl_Latn_NL
+ 0x998D434D4C61746ELLU, // nmg_Latn_CM
+ 0x6E6E4E4F4C61746ELLU, // nn_Latn_NO
+ 0x9DAD434D4C61746ELLU, // nnh_Latn_CM
+ 0x6E6F4E4F4C61746ELLU, // no_Latn_NO
+ 0x8DCD54484C616E61LLU, // nod_Lana_TH
+ 0x91CD494E44657661LLU, // noe_Deva_IN
+ 0xB5CD534552756E72LLU, // non_Runr_SE
+ 0xBA0D474E4E6B6F6FLLU, // nqo_Nkoo_GN
+ 0x6E725A414C61746ELLU, // nr_Latn_ZA
+ 0xAA4D434143616E73LLU, // nsk_Cans_CA
+ 0xBA4D5A414C61746ELLU, // nso_Latn_ZA
+ 0xCA8D53534C61746ELLU, // nus_Latn_SS
+ 0x6E7655534C61746ELLU, // nv_Latn_US
+ 0xC2ED434E4C61746ELLU, // nxq_Latn_CN
+ 0x6E794D574C61746ELLU, // ny_Latn_MW
+ 0xB30D545A4C61746ELLU, // nym_Latn_TZ
+ 0xB70D55474C61746ELLU, // nyn_Latn_UG
+ 0xA32D47484C61746ELLU, // nzi_Latn_GH
+ 0x6F6346524C61746ELLU, // oc_Latn_FR
+ 0x6F6D45544C61746ELLU, // om_Latn_ET
+ 0x6F72494E4F727961LLU, // or_Orya_IN
+ 0x6F7347454379726CLLU, // os_Cyrl_GE
+ 0x824E55534F736765LLU, // osa_Osge_US
+ 0xAA6E4D4E4F726B68LLU, // otk_Orkh_MN
+ 0x7061504B41726162LLU, // pa_Arab_PK
+ 0x7061494E47757275LLU, // pa_Guru_IN
+ 0x980F50484C61746ELLU, // pag_Latn_PH
+ 0xAC0F495250686C69LLU, // pal_Phli_IR
+ 0xAC0F434E50686C70LLU, // pal_Phlp_CN
+ 0xB00F50484C61746ELLU, // pam_Latn_PH
+ 0xBC0F41574C61746ELLU, // pap_Latn_AW
+ 0xD00F50574C61746ELLU, // pau_Latn_PW
+ 0x8C4F46524C61746ELLU, // pcd_Latn_FR
+ 0xB04F4E474C61746ELLU, // pcm_Latn_NG
+ 0x886F55534C61746ELLU, // pdc_Latn_US
+ 0xCC6F43414C61746ELLU, // pdt_Latn_CA
+ 0xB88F49525870656FLLU, // peo_Xpeo_IR
+ 0xACAF44454C61746ELLU, // pfl_Latn_DE
+ 0xB4EF4C4250686E78LLU, // phn_Phnx_LB
+ 0x814F494E42726168LLU, // pka_Brah_IN
+ 0xB94F4B454C61746ELLU, // pko_Latn_KE
+ 0x706C504C4C61746ELLU, // pl_Latn_PL
+ 0xC98F49544C61746ELLU, // pms_Latn_IT
+ 0xCDAF47524772656BLLU, // pnt_Grek_GR
+ 0xB5CF464D4C61746ELLU, // pon_Latn_FM
+ 0x822F504B4B686172LLU, // pra_Khar_PK
+ 0x8E2F495241726162LLU, // prd_Arab_IR
+ 0x7073414641726162LLU, // ps_Arab_AF
+ 0x707442524C61746ELLU, // pt_Latn_BR
+ 0xD28F47414C61746ELLU, // puu_Latn_GA
+ 0x717550454C61746ELLU, // qu_Latn_PE
+ 0x8A9047544C61746ELLU, // quc_Latn_GT
+ 0x9A9045434C61746ELLU, // qug_Latn_EC
+ 0xA411494E44657661LLU, // raj_Deva_IN
+ 0x945152454C61746ELLU, // rcf_Latn_RE
+ 0xA49149444C61746ELLU, // rej_Latn_ID
+ 0xB4D149544C61746ELLU, // rgn_Latn_IT
+ 0x8111494E4C61746ELLU, // ria_Latn_IN
+ 0x95114D4154666E67LLU, // rif_Tfng_MA
+ 0xC9314E5044657661LLU, // rjs_Deva_NP
+ 0xCD51424442656E67LLU, // rkt_Beng_BD
+ 0x726D43484C61746ELLU, // rm_Latn_CH
+ 0x959146494C61746ELLU, // rmf_Latn_FI
+ 0xB99143484C61746ELLU, // rmo_Latn_CH
+ 0xCD91495241726162LLU, // rmt_Arab_IR
+ 0xD19153454C61746ELLU, // rmu_Latn_SE
+ 0x726E42494C61746ELLU, // rn_Latn_BI
+ 0x99B14D5A4C61746ELLU, // rng_Latn_MZ
+ 0x726F524F4C61746ELLU, // ro_Latn_RO
+ 0x85D149444C61746ELLU, // rob_Latn_ID
+ 0x95D1545A4C61746ELLU, // rof_Latn_TZ
+ 0xB271464A4C61746ELLU, // rtm_Latn_FJ
+ 0x727552554379726CLLU, // ru_Cyrl_RU
+ 0x929155414379726CLLU, // rue_Cyrl_UA
+ 0x9A9153424C61746ELLU, // rug_Latn_SB
+ 0x727752574C61746ELLU, // rw_Latn_RW
+ 0xAAD1545A4C61746ELLU, // rwk_Latn_TZ
+ 0xD3114A504B616E61LLU, // ryu_Kana_JP
+ 0x7361494E44657661LLU, // sa_Deva_IN
+ 0x941247484C61746ELLU, // saf_Latn_GH
+ 0x9C1252554379726CLLU, // sah_Cyrl_RU
+ 0xC0124B454C61746ELLU, // saq_Latn_KE
+ 0xC81249444C61746ELLU, // sas_Latn_ID
+ 0xCC12494E4C61746ELLU, // sat_Latn_IN
+ 0xE412494E53617572LLU, // saz_Saur_IN
+ 0xBC32545A4C61746ELLU, // sbp_Latn_TZ
+ 0x736349544C61746ELLU, // sc_Latn_IT
+ 0xA852494E44657661LLU, // sck_Deva_IN
+ 0xB45249544C61746ELLU, // scn_Latn_IT
+ 0xB85247424C61746ELLU, // sco_Latn_GB
+ 0xC85243414C61746ELLU, // scs_Latn_CA
+ 0x7364504B41726162LLU, // sd_Arab_PK
+ 0x7364494E44657661LLU, // sd_Deva_IN
+ 0x7364494E4B686F6ALLU, // sd_Khoj_IN
+ 0x7364494E53696E64LLU, // sd_Sind_IN
+ 0x887249544C61746ELLU, // sdc_Latn_IT
+ 0x9C72495241726162LLU, // sdh_Arab_IR
+ 0x73654E4F4C61746ELLU, // se_Latn_NO
+ 0x949243494C61746ELLU, // sef_Latn_CI
+ 0x9C924D5A4C61746ELLU, // seh_Latn_MZ
+ 0xA0924D584C61746ELLU, // sei_Latn_MX
+ 0xC8924D4C4C61746ELLU, // ses_Latn_ML
+ 0x736743464C61746ELLU, // sg_Latn_CF
+ 0x80D249454F67616DLLU, // sga_Ogam_IE
+ 0xC8D24C544C61746ELLU, // sgs_Latn_LT
+ 0xA0F24D4154666E67LLU, // shi_Tfng_MA
+ 0xB4F24D4D4D796D72LLU, // shn_Mymr_MM
+ 0x73694C4B53696E68LLU, // si_Sinh_LK
+ 0x8D1245544C61746ELLU, // sid_Latn_ET
+ 0x736B534B4C61746ELLU, // sk_Latn_SK
+ 0xC552504B41726162LLU, // skr_Arab_PK
+ 0x736C53494C61746ELLU, // sl_Latn_SI
+ 0xA172504C4C61746ELLU, // sli_Latn_PL
+ 0xE17249444C61746ELLU, // sly_Latn_ID
+ 0x736D57534C61746ELLU, // sm_Latn_WS
+ 0x819253454C61746ELLU, // sma_Latn_SE
+ 0xA59253454C61746ELLU, // smj_Latn_SE
+ 0xB59246494C61746ELLU, // smn_Latn_FI
+ 0xBD92494C53616D72LLU, // smp_Samr_IL
+ 0xC99246494C61746ELLU, // sms_Latn_FI
+ 0x736E5A574C61746ELLU, // sn_Latn_ZW
+ 0xA9B24D4C4C61746ELLU, // snk_Latn_ML
+ 0x736F534F4C61746ELLU, // so_Latn_SO
+ 0xD1D2544854686169LLU, // sou_Thai_TH
+ 0x7371414C4C61746ELLU, // sq_Latn_AL
+ 0x737252534379726CLLU, // sr_Cyrl_RS
+ 0x737252534C61746ELLU, // sr_Latn_RS
+ 0x8632494E536F7261LLU, // srb_Sora_IN
+ 0xB63253524C61746ELLU, // srn_Latn_SR
+ 0xC632534E4C61746ELLU, // srr_Latn_SN
+ 0xDE32494E44657661LLU, // srx_Deva_IN
+ 0x73735A414C61746ELLU, // ss_Latn_ZA
+ 0xE25245524C61746ELLU, // ssy_Latn_ER
+ 0x73745A414C61746ELLU, // st_Latn_ZA
+ 0xC27244454C61746ELLU, // stq_Latn_DE
+ 0x737549444C61746ELLU, // su_Latn_ID
+ 0xAA92545A4C61746ELLU, // suk_Latn_TZ
+ 0xCA92474E4C61746ELLU, // sus_Latn_GN
+ 0x737653454C61746ELLU, // sv_Latn_SE
+ 0x7377545A4C61746ELLU, // sw_Latn_TZ
+ 0x86D2595441726162LLU, // swb_Arab_YT
+ 0x8AD243444C61746ELLU, // swc_Latn_CD
+ 0x9AD244454C61746ELLU, // swg_Latn_DE
+ 0xD6D2494E44657661LLU, // swv_Deva_IN
+ 0xB6F249444C61746ELLU, // sxn_Latn_ID
+ 0xAF12424442656E67LLU, // syl_Beng_BD
+ 0xC712495153797263LLU, // syr_Syrc_IQ
+ 0xAF32504C4C61746ELLU, // szl_Latn_PL
+ 0x7461494E54616D6CLLU, // ta_Taml_IN
+ 0xA4134E5044657661LLU, // taj_Deva_NP
+ 0xD83350484C61746ELLU, // tbw_Latn_PH
+ 0xE053494E4B6E6461LLU, // tcy_Knda_IN
+ 0x8C73434E54616C65LLU, // tdd_Tale_CN
+ 0x98734E5044657661LLU, // tdg_Deva_NP
+ 0x9C734E5044657661LLU, // tdh_Deva_NP
+ 0x7465494E54656C75LLU, // te_Telu_IN
+ 0xB093534C4C61746ELLU, // tem_Latn_SL
+ 0xB89355474C61746ELLU, // teo_Latn_UG
+ 0xCC93544C4C61746ELLU, // tet_Latn_TL
+ 0x7467504B41726162LLU, // tg_Arab_PK
+ 0x7467544A4379726CLLU, // tg_Cyrl_TJ
+ 0x7468544854686169LLU, // th_Thai_TH
+ 0xACF34E5044657661LLU, // thl_Deva_NP
+ 0xC0F34E5044657661LLU, // thq_Deva_NP
+ 0xC4F34E5044657661LLU, // thr_Deva_NP
+ 0x7469455445746869LLU, // ti_Ethi_ET
+ 0x9913455245746869LLU, // tig_Ethi_ER
+ 0xD5134E474C61746ELLU, // tiv_Latn_NG
+ 0x746B544D4C61746ELLU, // tk_Latn_TM
+ 0xAD53544B4C61746ELLU, // tkl_Latn_TK
+ 0xC553415A4C61746ELLU, // tkr_Latn_AZ
+ 0xCD534E5044657661LLU, // tkt_Deva_NP
+ 0x746C50484C61746ELLU, // tl_Latn_PH
+ 0xE173415A4C61746ELLU, // tly_Latn_AZ
+ 0x9D934E454C61746ELLU, // tmh_Latn_NE
+ 0x746E5A414C61746ELLU, // tn_Latn_ZA
+ 0x746F544F4C61746ELLU, // to_Latn_TO
+ 0x99D34D574C61746ELLU, // tog_Latn_MW
+ 0xA1F350474C61746ELLU, // tpi_Latn_PG
+ 0x747254524C61746ELLU, // tr_Latn_TR
+ 0xD23354524C61746ELLU, // tru_Latn_TR
+ 0xD63354574C61746ELLU, // trv_Latn_TW
+ 0x74735A414C61746ELLU, // ts_Latn_ZA
+ 0x8E5347524772656BLLU, // tsd_Grek_GR
+ 0x96534E5044657661LLU, // tsf_Deva_NP
+ 0x9A5350484C61746ELLU, // tsg_Latn_PH
+ 0xA653425454696274LLU, // tsj_Tibt_BT
+ 0x747452554379726CLLU, // tt_Cyrl_RU
+ 0xA67355474C61746ELLU, // ttj_Latn_UG
+ 0xCA73544854686169LLU, // tts_Thai_TH
+ 0xCE73415A4C61746ELLU, // ttt_Latn_AZ
+ 0xB2934D574C61746ELLU, // tum_Latn_MW
+ 0xAEB354564C61746ELLU, // tvl_Latn_TV
+ 0xC2D34E454C61746ELLU, // twq_Latn_NE
+ 0x9AF3434E54616E67LLU, // txg_Tang_CN
+ 0x747950464C61746ELLU, // ty_Latn_PF
+ 0xD71352554379726CLLU, // tyv_Cyrl_RU
+ 0xB3334D414C61746ELLU, // tzm_Latn_MA
+ 0xB07452554379726CLLU, // udm_Cyrl_RU
+ 0x7567434E41726162LLU, // ug_Arab_CN
+ 0x75674B5A4379726CLLU, // ug_Cyrl_KZ
+ 0x80D4535955676172LLU, // uga_Ugar_SY
+ 0x756B55414379726CLLU, // uk_Cyrl_UA
+ 0xA174464D4C61746ELLU, // uli_Latn_FM
+ 0x8594414F4C61746ELLU, // umb_Latn_AO
+ 0xC5B4494E42656E67LLU, // unr_Beng_IN
+ 0xC5B44E5044657661LLU, // unr_Deva_NP
+ 0xDDB4494E42656E67LLU, // unx_Beng_IN
+ 0x7572504B41726162LLU, // ur_Arab_PK
+ 0x757A414641726162LLU, // uz_Arab_AF
+ 0x757A555A4C61746ELLU, // uz_Latn_UZ
+ 0xA0154C5256616969LLU, // vai_Vaii_LR
+ 0x76655A414C61746ELLU, // ve_Latn_ZA
+ 0x889549544C61746ELLU, // vec_Latn_IT
+ 0xBC9552554C61746ELLU, // vep_Latn_RU
+ 0x7669564E4C61746ELLU, // vi_Latn_VN
+ 0x891553584C61746ELLU, // vic_Latn_SX
+ 0xC97542454C61746ELLU, // vls_Latn_BE
+ 0x959544454C61746ELLU, // vmf_Latn_DE
+ 0xD9954D5A4C61746ELLU, // vmw_Latn_MZ
+ 0xCDD552554C61746ELLU, // vot_Latn_RU
+ 0xBA3545454C61746ELLU, // vro_Latn_EE
+ 0xB695545A4C61746ELLU, // vun_Latn_TZ
+ 0x776142454C61746ELLU, // wa_Latn_BE
+ 0x901643484C61746ELLU, // wae_Latn_CH
+ 0xAC16455445746869LLU, // wal_Ethi_ET
+ 0xC41650484C61746ELLU, // war_Latn_PH
+ 0xBC3641554C61746ELLU, // wbp_Latn_AU
+ 0xC036494E54656C75LLU, // wbq_Telu_IN
+ 0xC436494E44657661LLU, // wbr_Deva_IN
+ 0xC97657464C61746ELLU, // wls_Latn_WF
+ 0xA1B64B4D41726162LLU, // wni_Arab_KM
+ 0x776F534E4C61746ELLU, // wo_Latn_SN
+ 0xB276494E44657661LLU, // wtm_Deva_IN
+ 0xD296434E48616E73LLU, // wuu_Hans_CN
+ 0xD41742524C61746ELLU, // xav_Latn_BR
+ 0xC457545243617269LLU, // xcr_Cari_TR
+ 0x78685A414C61746ELLU, // xh_Latn_ZA
+ 0x897754524C796369LLU, // xlc_Lyci_TR
+ 0x8D7754524C796469LLU, // xld_Lydi_TR
+ 0x9597474547656F72LLU, // xmf_Geor_GE
+ 0xB597434E4D616E69LLU, // xmn_Mani_CN
+ 0xC59753444D657263LLU, // xmr_Merc_SD
+ 0x81B753414E617262LLU, // xna_Narb_SA
+ 0xC5B7494E44657661LLU, // xnr_Deva_IN
+ 0x99D755474C61746ELLU, // xog_Latn_UG
+ 0xC5F7495250727469LLU, // xpr_Prti_IR
+ 0x8257594553617262LLU, // xsa_Sarb_YE
+ 0xC6574E5044657661LLU, // xsr_Deva_NP
+ 0xB8184D5A4C61746ELLU, // yao_Latn_MZ
+ 0xBC18464D4C61746ELLU, // yap_Latn_FM
+ 0xD418434D4C61746ELLU, // yav_Latn_CM
+ 0x8438434D4C61746ELLU, // ybb_Latn_CM
+ 0x796F4E474C61746ELLU, // yo_Latn_NG
+ 0xAE3842524C61746ELLU, // yrl_Latn_BR
+ 0x82984D584C61746ELLU, // yua_Latn_MX
+ 0x9298434E48616E73LLU, // yue_Hans_CN
+ 0x9298484B48616E74LLU, // yue_Hant_HK
+ 0x7A61434E4C61746ELLU, // za_Latn_CN
+ 0x981953444C61746ELLU, // zag_Latn_SD
+ 0xA4794B4D41726162LLU, // zdj_Arab_KM
+ 0x80994E4C4C61746ELLU, // zea_Latn_NL
+ 0x9CD94D4154666E67LLU, // zgh_Tfng_MA
+ 0x7A685457426F706FLLU, // zh_Bopo_TW
+ 0x7A68545748616E62LLU, // zh_Hanb_TW
+ 0x7A68434E48616E73LLU, // zh_Hans_CN
+ 0x7A68545748616E74LLU, // zh_Hant_TW
+ 0xB17954474C61746ELLU, // zlm_Latn_TG
+ 0xA1994D594C61746ELLU, // zmi_Latn_MY
+ 0x7A755A414C61746ELLU, // zu_Latn_ZA
+ 0x833954524C61746ELLU, // zza_Latn_TR
});
const std::unordered_map<uint32_t, uint32_t> ARAB_PARENTS({
diff --git a/libs/androidfw/OWNERS b/libs/androidfw/OWNERS
index 23ec5ab0d1f3..f1903a5a54a7 100644
--- a/libs/androidfw/OWNERS
+++ b/libs/androidfw/OWNERS
@@ -1,2 +1,3 @@
set noparent
toddke@google.com
+rtmitchell@google.com \ No newline at end of file
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 2fe98b00f3a2..63b25270f116 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -7076,7 +7076,7 @@ public:
}
}
- const auto& getTypeMapping() const {
+ const std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>>& getTypeMapping() const {
return mTypeMapping->mData;
}
@@ -7137,9 +7137,6 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
const PackageGroup* packageGroup = mPackageGroups[0];
- // the number of resources overlaid that were not explicitly marked overlayable
- size_t forcedOverlayCount = 0u;
-
// find the resources that exist in both packages
auto typeMapping = std::make_unique<IdmapTypeMapping>();
for (size_t typeIndex = 0; typeIndex < packageGroup->types.size(); ++typeIndex) {
@@ -7170,11 +7167,6 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
continue;
}
- if ((dtohl(typeConfigs->typeSpecFlags[entryIndex]) &
- ResTable_typeSpec::SPEC_OVERLAYABLE) == 0) {
- ++forcedOverlayCount;
- }
-
typeMapping->add(target_resid, overlay_resid);
}
}
@@ -7243,10 +7235,6 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
typeData += entryCount * 2;
}
- if (forcedOverlayCount > 0) {
- ALOGW("idmap: overlaid %zu resources not marked overlayable", forcedOverlayCount);
- }
-
return NO_ERROR;
}
diff --git a/libs/androidfw/TEST_MAPPING b/libs/androidfw/TEST_MAPPING
new file mode 100644
index 000000000000..a58b47fcff9d
--- /dev/null
+++ b/libs/androidfw/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+ "presubmit": [
+ {
+ "name": "libandroidfw_tests",
+ "host": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/libs/androidfw/include/androidfw/Chunk.h b/libs/androidfw/include/androidfw/Chunk.h
index 99a52dc9244e..a0f23433c676 100644
--- a/libs/androidfw/include/androidfw/Chunk.h
+++ b/libs/androidfw/include/androidfw/Chunk.h
@@ -89,7 +89,9 @@ class ChunkIterator {
len_(len),
last_error_(nullptr) {
CHECK(next_chunk_ != nullptr) << "data can't be nullptr";
- VerifyNextChunk();
+ if (len_ != 0) {
+ VerifyNextChunk();
+ }
}
Chunk Next();
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 349b379778a6..8c5c3b7d3858 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -20,6 +20,7 @@
#include <memory>
#include <set>
#include <vector>
+#include <unordered_set>
#include "android-base/macros.h"
@@ -76,6 +77,10 @@ struct TypeSpec {
// TypeSpecPtr is a managed pointer that knows how to delete itself.
using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+struct OverlayableInfo {
+ uint32_t policy_flags;
+};
+
class LoadedPackage {
public:
class iterator {
@@ -216,6 +221,18 @@ class LoadedPackage {
}
}
+ // Retrieve the overlayable properties of the specified resource. If the resource is not
+ // overlayable, this will return a null pointer.
+ const OverlayableInfo* GetOverlayableInfo(uint32_t resid) const {
+ for (const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>& overlayable_info_ids
+ : overlayable_infos_) {
+ if (overlayable_info_ids.second.find(resid) != overlayable_info_ids.second.end()) {
+ return &overlayable_info_ids.first;
+ }
+ }
+ return nullptr;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
@@ -233,6 +250,7 @@ class LoadedPackage {
ByteBucketArray<TypeSpecPtr> type_specs_;
ByteBucketArray<uint32_t> resource_ids_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
+ std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
};
// Read-only view into a resource table. This class validates all data
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index ad33fcfa2429..cf2d8fb3251c 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -234,7 +234,9 @@ enum {
RES_TABLE_PACKAGE_TYPE = 0x0200,
RES_TABLE_TYPE_TYPE = 0x0201,
RES_TABLE_TYPE_SPEC_TYPE = 0x0202,
- RES_TABLE_LIBRARY_TYPE = 0x0203
+ RES_TABLE_LIBRARY_TYPE = 0x0203,
+ RES_TABLE_OVERLAYABLE_TYPE = 0x0204,
+ RES_TABLE_OVERLAYABLE_POLICY_TYPE = 0x0205,
};
/**
@@ -1354,10 +1356,6 @@ struct ResTable_typeSpec
enum : uint32_t {
// Additional flag indicating an entry is public.
SPEC_PUBLIC = 0x40000000u,
-
- // Additional flag indicating an entry is overlayable at runtime.
- // Added in Android-P.
- SPEC_OVERLAYABLE = 0x80000000u,
};
};
@@ -1607,6 +1605,49 @@ struct ResTable_lib_entry
uint16_t packageName[128];
};
+/**
+ * Specifies the set of resources that are explicitly allowed to be overlaid by RROs.
+ */
+struct ResTable_overlayable_header
+{
+ struct ResChunk_header header;
+};
+
+/**
+ * Holds a list of resource ids that are protected from being overlaid by a set of policies. If
+ * the overlay fulfils at least one of the policies, then the overlay can overlay the list of
+ * resources.
+ */
+struct ResTable_overlayable_policy_header
+{
+ struct ResChunk_header header;
+
+ enum PolicyFlags : uint32_t {
+ // Any overlay can overlay these resources.
+ POLICY_PUBLIC = 0x00000001,
+
+ // The overlay must reside of the system partition or must have existed on the system partition
+ // before an upgrade to overlay these resources.
+ POLICY_SYSTEM_PARTITION = 0x00000002,
+
+ // The overlay must reside of the vendor partition or must have existed on the vendor partition
+ // before an upgrade to overlay these resources.
+ POLICY_VENDOR_PARTITION = 0x00000004,
+
+ // The overlay must reside of the product partition or must have existed on the product
+ // partition before an upgrade to overlay these resources.
+ POLICY_PRODUCT_PARTITION = 0x00000008,
+
+ // The overlay must reside of the product services partition or must have existed on the product
+ // services partition before an upgrade to overlay these resources.
+ POLICY_PRODUCT_SERVICES_PARTITION = 0x00000010,
+ };
+ uint32_t policy_flags;
+
+ // The number of ResTable_ref that follow this header.
+ uint32_t entry_count;
+};
+
struct alignas(uint32_t) Idmap_header {
// Always 0x504D4449 ('IDMP')
uint32_t magic;
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index ffa48367c252..22d587a7f5c4 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -22,12 +22,14 @@
#include "TestHelpers.h"
#include "data/basic/R.h"
#include "data/libclient/R.h"
+#include "data/overlayable/R.h"
#include "data/sparse/R.h"
#include "data/styles/R.h"
namespace app = com::android::app;
namespace basic = com::android::basic;
namespace libclient = com::android::libclient;
+namespace overlayable = com::android::overlayable;
namespace sparse = com::android::sparse;
using ::android::base::ReadFileToString;
@@ -273,10 +275,44 @@ TEST(LoadedArscTest, LoadOverlay) {
ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0000), NotNull());
}
-// structs with size fields (like Res_value, ResTable_entry) should be
-// backwards and forwards compatible (aka checking the size field against
-// sizeof(Res_value) might not be backwards compatible.
-TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+TEST(LoadedArscTest, LoadOverlayable) {
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
+ "resources.arsc", &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc =
+ LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
+ false /*load_as_shared_library*/);
+
+ ASSERT_THAT(loaded_arsc, NotNull());
+ const LoadedPackage* package = loaded_arsc->GetPackageById(
+ get_package_id(overlayable::R::string::not_overlayable));
+
+ const OverlayableInfo* info = package->GetOverlayableInfo(
+ overlayable::R::string::not_overlayable);
+ ASSERT_THAT(info, IsNull());
+
+ info = package->GetOverlayableInfo(overlayable::R::string::overlayable1);
+ ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
+
+ info = package->GetOverlayableInfo(overlayable::R::string::overlayable2);
+ ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->policy_flags,
+ Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION
+ | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
+
+ info = package->GetOverlayableInfo(overlayable::R::string::overlayable3);
+ ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->policy_flags,
+ Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
+ | ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION
+ | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
+
+ info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
+ ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
+}
TEST(LoadedArscTest, ResourceIdentifierIterator) {
std::string contents;
@@ -326,4 +362,9 @@ TEST(LoadedArscTest, ResourceIdentifierIterator) {
ASSERT_EQ(end, iter);
}
+// structs with size fields (like Res_value, ResTable_entry) should be
+// backwards and forwards compatible (aka checking the size field against
+// sizeof(Res_value) might not be backwards compatible.
+// TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+
} // namespace android
diff --git a/libs/androidfw/tests/data/overlay/overlay.apk b/libs/androidfw/tests/data/overlay/overlay.apk
index 33f961117c44..d37874dcbb40 100644
--- a/libs/androidfw/tests/data/overlay/overlay.apk
+++ b/libs/androidfw/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/AndroidManifest.xml b/libs/androidfw/tests/data/overlayable/AndroidManifest.xml
new file mode 100644
index 000000000000..abc2a454e845
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlayable">
+ <application>
+ </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/overlayable/R.h b/libs/androidfw/tests/data/overlayable/R.h
new file mode 100644
index 000000000000..e46e264da318
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/R.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef TESTS_DATA_OVERLAYABLE_R_H_
+#define TESTS_DATA_OVERLAYABLE_R_H_
+
+#include <cstdint>
+
+namespace com {
+namespace android {
+namespace overlayable {
+
+struct R {
+ struct string {
+ enum : uint32_t {
+ not_overlayable = 0x7f010000,
+ overlayable1 = 0x7f010001,
+ overlayable2 = 0x7f010002,
+ overlayable3 = 0x7f010003,
+ overlayable4 = 0x7f010004,
+ };
+ };
+};
+
+} // namespace overlayable
+} // namespace android
+} // namespace com
+
+#endif /* TESTS_DATA_OVERLAYABLE_R_H_ */
diff --git a/libs/androidfw/tests/data/overlayable/build b/libs/androidfw/tests/data/overlayable/build
new file mode 100755
index 000000000000..98fdc5101160
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/build
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# 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.
+#
+
+set -e
+
+aapt2 compile --dir res -o compiled.flata
+aapt2 link --manifest AndroidManifest.xml -o overlayable.apk compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
new file mode 100644
index 000000000000..85ab4be7a2e5
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
new file mode 100644
index 000000000000..11aa7354901d
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+<overlayable>
+ <!-- Any overlay can overlay the value of @string/overlayable1 -->
+ <item type="string" name="overlayable1" />
+
+ <!-- Any overlay on the product or system partition can overlay the value of
+ @string/overlayable2 -->
+ <policy type="product|system">
+ <item type="string" name="overlayable2" />
+ </policy>
+
+ <!-- Any overlay can overlay the value of @string/overlayable4 -->
+ <policy type="public">
+ <item type="string" name="overlayable4" />
+ </policy>
+</overlayable>
+
+<overlayable>
+ <!-- Any overlay on the product_services, vendor, or product partition can overlay the value of
+ @string/overlayable3 -->
+ <policy type="product_services|vendor|product">
+ <item type="string" name="overlayable3" />
+ </policy>
+</overlayable>
+</resources> \ No newline at end of file
diff --git a/libs/androidfw/tests/data/overlayable/res/values/public.xml b/libs/androidfw/tests/data/overlayable/res/values/public.xml
new file mode 100644
index 000000000000..5676d7cc64c9
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/res/values/public.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <public type="string" name="not_overlayable" id="0x7f010000" />
+ <public type="string" name="overlayable1" id="0x7f010001" />
+ <public type="string" name="overlayable2" id="0x7f010002" />
+ <public type="string" name="overlayable3" id="0x7f010003" />
+ <public type="string" name="overlayable4" id="0x7f010004" />
+</resources> \ No newline at end of file
diff --git a/libs/androidfw/tests/data/overlayable/res/values/values.xml b/libs/androidfw/tests/data/overlayable/res/values/values.xml
new file mode 100644
index 000000000000..a86b31282bc9
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/res/values/values.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources>
+ <string name="not_overlayable">Not overlayable</string>
+ <string name="overlayable1">Overlayable One</string>
+ <string name="overlayable2">Overlayable Two</string>
+ <string name="overlayable3">Overlayable Three</string>
+ <string name="overlayable4">Overlayable Four</string>
+</resources>
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index da77b99e6e53..96798f978465 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -9,6 +9,8 @@ cc_defaults {
"hwui_lto",
],
+ cpp_std: "experimental",
+
cflags: [
"-DEGL_EGLEXT_PROTOTYPES",
"-DGL_GLEXT_PROTOTYPES",
@@ -59,7 +61,9 @@ cc_defaults {
"libstatslog",
"libutils",
"libEGL",
+ "libGLESv1_CM",
"libGLESv2",
+ "libGLESv3",
"libvulkan",
"libui",
"libgui",
@@ -171,12 +175,14 @@ cc_defaults {
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/SkiaVulkanPipeline.cpp",
"pipeline/skia/VectorDrawableAtlas.cpp",
+ "pipeline/skia/VkFunctorDrawable.cpp",
"pipeline/skia/VkInteropFunctorDrawable.cpp",
"renderstate/RenderState.cpp",
"renderthread/CacheManager.cpp",
"renderthread/CanvasContext.cpp",
"renderthread/DrawFrameTask.cpp",
"renderthread/EglManager.cpp",
+ "renderthread/ReliableSurface.cpp",
"renderthread/VulkanManager.cpp",
"renderthread/RenderProxy.cpp",
"renderthread/RenderTask.cpp",
@@ -205,6 +211,7 @@ cc_defaults {
"FrameInfoVisualizer.cpp",
"GpuMemoryTracker.cpp",
"HardwareBitmapUploader.cpp",
+ "HWUIProperties.sysprop",
"Interpolator.cpp",
"JankTracker.cpp",
"Layer.cpp",
@@ -222,6 +229,7 @@ cc_defaults {
"RenderProperties.cpp",
"SkiaCanvas.cpp",
"TreeInfo.cpp",
+ "WebViewFunctorManager.cpp",
"VectorDrawable.cpp",
"protos/graphicsstats.proto",
],
@@ -326,6 +334,7 @@ cc_test {
"tests/unit/TypefaceTests.cpp",
"tests/unit/VectorDrawableTests.cpp",
"tests/unit/VectorDrawableAtlasTests.cpp",
+ "tests/unit/WebViewFunctorManagerTests.cpp",
],
}
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 0b9d82b105a3..ed167e57158e 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -20,6 +20,7 @@
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
+#include <ui/GraphicTypes.h>
#include <mutex>
#include <thread>
@@ -61,6 +62,50 @@ DisplayInfo QueryDisplayInfo() {
return displayInfo;
}
+static void queryWideColorGamutPreference(SkColorSpace::Gamut* colorGamut,
+ sk_sp<SkColorSpace>* colorSpace, SkColorType* colorType) {
+ if (Properties::isolatedProcess) {
+ *colorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
+ *colorSpace = SkColorSpace::MakeSRGB();
+ *colorType = SkColorType::kN32_SkColorType;
+ return;
+ }
+ ui::Dataspace defaultDataspace, wcgDataspace;
+ ui::PixelFormat defaultPixelFormat, wcgPixelFormat;
+ status_t status =
+ SurfaceComposerClient::getCompositionPreference(&defaultDataspace, &defaultPixelFormat,
+ &wcgDataspace, &wcgPixelFormat);
+ LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status);
+ switch (wcgDataspace) {
+ case ui::Dataspace::DISPLAY_P3:
+ *colorGamut = SkColorSpace::Gamut::kDCIP3_D65_Gamut;
+ *colorSpace = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
+ SkColorSpace::Gamut::kDCIP3_D65_Gamut);
+ break;
+ case ui::Dataspace::V0_SCRGB:
+ *colorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
+ *colorSpace = SkColorSpace::MakeSRGB();
+ break;
+ case ui::Dataspace::V0_SRGB:
+ // when sRGB is returned, it means wide color gamut is not supported.
+ *colorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
+ *colorSpace = SkColorSpace::MakeSRGB();
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ }
+ switch (wcgPixelFormat) {
+ case ui::PixelFormat::RGBA_8888:
+ *colorType = SkColorType::kN32_SkColorType;
+ break;
+ case ui::PixelFormat::RGBA_FP16:
+ *colorType = SkColorType::kRGBA_F16_SkColorType;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format.");
+ }
+}
+
DeviceInfo::DeviceInfo() {
#if HWUI_NULL_GPU
mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE;
@@ -68,6 +113,7 @@ DeviceInfo::DeviceInfo() {
mMaxTextureSize = -1;
#endif
mDisplayInfo = QueryDisplayInfo();
+ queryWideColorGamutPreference(&mWideColorGamut, &mWideColorSpace, &mWideColorType);
}
int DeviceInfo::maxTextureSize() const {
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 595621573e6e..9bcc8e8a3dbe 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -16,6 +16,7 @@
#ifndef DEVICEINFO_H
#define DEVICEINFO_H
+#include <SkImageInfo.h>
#include <ui/DisplayInfo.h>
#include "utils/Macros.h"
@@ -37,6 +38,9 @@ public:
// context or if you are using the HWUI_NULL_GPU
int maxTextureSize() const;
const DisplayInfo& displayInfo() const { return mDisplayInfo; }
+ SkColorSpace::Gamut getWideColorGamut() const { return mWideColorGamut; }
+ sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
+ SkColorType getWideColorType() const { return mWideColorType; }
private:
friend class renderthread::RenderThread;
@@ -46,6 +50,9 @@ private:
int mMaxTextureSize;
DisplayInfo mDisplayInfo;
+ SkColorSpace::Gamut mWideColorGamut;
+ sk_sp<SkColorSpace> mWideColorSpace;
+ SkColorType mWideColorType;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index 04cf611c8322..14e3a32817a0 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -18,6 +18,7 @@ X(Flush)
X(Save)
X(Restore)
X(SaveLayer)
+X(SaveBehind)
X(Concat)
X(SetMatrix)
X(Translate)
@@ -40,14 +41,10 @@ X(DrawImage)
X(DrawImageNine)
X(DrawImageRect)
X(DrawImageLattice)
-X(DrawText)
-X(DrawPosText)
-X(DrawPosTextH)
-X(DrawTextRSXform)
X(DrawTextBlob)
X(DrawPatch)
X(DrawPoints)
X(DrawVertices)
X(DrawAtlas)
X(DrawShadowRec)
-X(DrawVectorDrawable) \ No newline at end of file
+X(DrawVectorDrawable)
diff --git a/libs/hwui/HWUIProperties.sysprop b/libs/hwui/HWUIProperties.sysprop
new file mode 100644
index 000000000000..42191ca6f514
--- /dev/null
+++ b/libs/hwui/HWUIProperties.sysprop
@@ -0,0 +1,9 @@
+owner: Platform
+module: "android.uirenderer"
+prop {
+ api_name: "use_vulkan"
+ type: Boolean
+ prop_name: "ro.hwui.use_vulkan"
+ scope: Public
+ access: Readonly
+}
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index a97c12cad9fd..635d0ec66673 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -34,7 +34,7 @@
namespace android::uirenderer {
static std::mutex sLock{};
-static ThreadBase* sUploadThread = nullptr;
+static sp<ThreadBase> sUploadThread = nullptr;
static renderthread::EglManager sEglManager;
static int sPendingUploads = 0;
static nsecs_t sLastUpload = 0;
@@ -253,7 +253,19 @@ sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sou
eglDestroySyncKHR(display, fence);
}
- return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info(), Bitmap::computePalette(bitmap)));
+ return Bitmap::createFrom(buffer.get(), bitmap.refColorSpace(), bitmap.alphaType(),
+ Bitmap::computePalette(bitmap));
+}
+
+void HardwareBitmapUploader::terminate() {
+ std::lock_guard _lock{sLock};
+ LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress");
+ if (sUploadThread) {
+ sUploadThread->requestExit();
+ sUploadThread->join();
+ sUploadThread = nullptr;
+ }
+ sEglManager.destroy();
}
} // namespace android::uirenderer
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 6298013bd263..40f2b0c7873c 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -23,6 +23,7 @@ namespace android::uirenderer {
class HardwareBitmapUploader {
public:
static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+ static void terminate();
};
} // namespace android::uirenderer
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index b33cfe2ec511..0c515a41689d 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -81,7 +81,7 @@ public:
explicit Matrix4(const float* v) { load(v); }
- Matrix4(const SkMatrix& v) { // NOLINT, implicit
+ Matrix4(const SkMatrix& v) { // NOLINT(google-explicit-constructor)
load(v);
}
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 4a3e10c54cef..046ffc4da5ea 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -18,6 +18,7 @@
#include "Debug.h"
#include "DeviceInfo.h"
#include "SkTraceEventCommon.h"
+#include "HWUIProperties.sysprop.h"
#include <algorithm>
#include <cstdlib>
@@ -29,8 +30,6 @@
namespace android {
namespace uirenderer {
-bool Properties::drawDeferDisabled = false;
-bool Properties::drawReorderDisabled = false;
bool Properties::debugLayersUpdates = false;
bool Properties::debugOverdraw = false;
bool Properties::showDirtyRegions = false;
@@ -40,7 +39,6 @@ bool Properties::enablePartialUpdates = true;
DebugLevel Properties::debugLevel = kDebugDisabled;
OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default;
-StencilClipDebug Properties::debugStencilClip = StencilClipDebug::Hide;
float Properties::overrideLightRadius = -1.0f;
float Properties::overrideLightPosY = -1.0f;
@@ -85,7 +83,6 @@ bool Properties::load() {
char property[PROPERTY_VALUE_MAX];
bool prevDebugLayersUpdates = debugLayersUpdates;
bool prevDebugOverdraw = debugOverdraw;
- StencilClipDebug prevDebugStencilClip = debugStencilClip;
debugOverdraw = false;
if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) {
@@ -99,20 +96,6 @@ bool Properties::load() {
}
}
- // See Properties.h for valid values
- if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, nullptr) > 0) {
- INIT_LOGD(" Stencil clip debug enabled: %s", property);
- if (!strcmp(property, "hide")) {
- debugStencilClip = StencilClipDebug::Hide;
- } else if (!strcmp(property, "highlight")) {
- debugStencilClip = StencilClipDebug::ShowHighlight;
- } else if (!strcmp(property, "region")) {
- debugStencilClip = StencilClipDebug::ShowRegion;
- }
- } else {
- debugStencilClip = StencilClipDebug::Hide;
- }
-
sProfileType = ProfileType::None;
if (property_get(PROPERTY_PROFILE, property, "") > 0) {
if (!strcmp(property, PROPERTY_PROFILE_VISUALIZE_BARS)) {
@@ -125,12 +108,6 @@ bool Properties::load() {
debugLayersUpdates = property_get_bool(PROPERTY_DEBUG_LAYERS_UPDATES, false);
INIT_LOGD(" Layers updates debug enabled: %d", debugLayersUpdates);
- drawDeferDisabled = property_get_bool(PROPERTY_DISABLE_DRAW_DEFER, false);
- INIT_LOGD(" Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
-
- drawReorderDisabled = property_get_bool(PROPERTY_DISABLE_DRAW_REORDER, false);
- INIT_LOGD(" Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
-
showDirtyRegions = property_get_bool(PROPERTY_DEBUG_SHOW_DIRTY_REGIONS, false);
debugLevel = (DebugLevel)property_get_int(PROPERTY_DEBUG, kDebugDisabled);
@@ -152,8 +129,7 @@ bool Properties::load() {
enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, true);
- return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||
- (prevDebugStencilClip != debugStencilClip);
+ return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
}
void Properties::overrideProperty(const char* name, const char* value) {
@@ -199,8 +175,13 @@ RenderPipelineType Properties::getRenderPipelineType() {
if (sRenderPipelineType != RenderPipelineType::NotInitialized) {
return sRenderPipelineType;
}
+ bool useVulkan = use_vulkan().value_or(false);
char prop[PROPERTY_VALUE_MAX];
- property_get(PROPERTY_RENDERER, prop, "skiagl");
+ if (useVulkan) {
+ property_get(PROPERTY_RENDERER, prop, "skiavk");
+ } else {
+ property_get(PROPERTY_RENDERER, prop, "skiagl");
+ }
if (!strcmp(prop, "skiavk")) {
ALOGD("Skia Vulkan Pipeline");
sRenderPipelineType = RenderPipelineType::SkiaVulkan;
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index da53f6657ff7..0a7f4e7eb41c 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -95,20 +95,6 @@ enum DebugLevel {
#define PROPERTY_PROFILE_VISUALIZE_BARS "visual_bars"
/**
- * Used to enable/disable non-rectangular clipping debugging.
- *
- * The accepted values are:
- * "highlight", drawing commands clipped by the stencil will
- * be colored differently
- * "region", renders the clipping region on screen whenever
- * the stencil is set
- * "hide", don't show the clip
- *
- * The default value is "hide".
- */
-#define PROPERTY_DEBUG_STENCIL_CLIP "debug.hwui.show_non_rect_clip"
-
-/**
* Turn on to draw dirty regions every other frame.
*
* Possible values:
@@ -118,19 +104,6 @@ enum DebugLevel {
#define PROPERTY_DEBUG_SHOW_DIRTY_REGIONS "debug.hwui.show_dirty_regions"
/**
- * Disables draw operation deferral if set to "true", forcing draw
- * commands to be issued to OpenGL in order, and processed in sequence
- * with state-manipulation canvas commands.
- */
-#define PROPERTY_DISABLE_DRAW_DEFER "debug.hwui.disable_draw_defer"
-
-/**
- * Used to disable draw operation reordering when deferring draw operations
- * Has no effect if PROPERTY_DISABLE_DRAW_DEFER is set to "true"
- */
-#define PROPERTY_DISABLE_DRAW_REORDER "debug.hwui.disable_draw_reorder"
-
-/**
* Setting this property will enable or disable the dropping of frames with
* empty damage. Default is "true".
*/
@@ -207,8 +180,6 @@ enum class ProfileType { None, Console, Bars };
enum class OverdrawColorSet { Default = 0, Deuteranomaly };
-enum class StencilClipDebug { Hide, ShowHighlight, ShowRegion };
-
enum class RenderPipelineType { SkiaGL, SkiaVulkan, NotInitialized = 128 };
/**
@@ -220,8 +191,6 @@ class Properties {
public:
static bool load();
- static bool drawDeferDisabled;
- static bool drawReorderDisabled;
static bool debugLayersUpdates;
static bool debugOverdraw;
static bool showDirtyRegions;
@@ -235,7 +204,6 @@ public:
static DebugLevel debugLevel;
static OverdrawColorSet overdrawColorSet;
- static StencilClipDebug debugStencilClip;
// Override the value for a subset of properties in this class
static void overrideProperty(const char* name, const char* value);
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index c63e449319dd..6dc9d34cc3fd 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -18,6 +18,7 @@
#include "VectorDrawable.h"
+#include "SkAndroidFrameworkUtils.h"
#include "SkCanvas.h"
#include "SkData.h"
#include "SkDrawShadowInfo.h"
@@ -116,6 +117,16 @@ struct SaveLayer final : Op {
clipMatrix.isIdentity() ? nullptr : &clipMatrix, flags});
}
};
+struct SaveBehind final : Op {
+ static const auto kType = Type::SaveBehind;
+ SaveBehind(const SkRect* subset) {
+ if (subset) { this->subset = *subset; }
+ }
+ SkRect subset = kUnset;
+ void draw(SkCanvas* c, const SkMatrix&) const {
+ SkAndroidFrameworkUtils::SaveBehind(c, &subset);
+ }
+};
struct Concat final : Op {
static const auto kType = Type::Concat;
@@ -362,61 +373,6 @@ struct DrawImageLattice final : Op {
}
};
-struct DrawText final : Op {
- static const auto kType = Type::DrawText;
- DrawText(size_t bytes, SkScalar x, SkScalar y, const SkPaint& paint)
- : bytes(bytes), x(x), y(y), paint(paint) {}
- size_t bytes;
- SkScalar x, y;
- SkPaint paint;
- void draw(SkCanvas* c, const SkMatrix&) const {
- c->drawText(pod<void>(this), bytes, x, y, paint);
- }
-};
-struct DrawPosText final : Op {
- static const auto kType = Type::DrawPosText;
- DrawPosText(size_t bytes, const SkPaint& paint, int n) : bytes(bytes), paint(paint), n(n) {}
- size_t bytes;
- SkPaint paint;
- int n;
- void draw(SkCanvas* c, const SkMatrix&) const {
- auto points = pod<SkPoint>(this);
- auto text = pod<void>(this, n * sizeof(SkPoint));
- c->drawPosText(text, bytes, points, paint);
- }
-};
-struct DrawPosTextH final : Op {
- static const auto kType = Type::DrawPosTextH;
- DrawPosTextH(size_t bytes, SkScalar y, const SkPaint& paint, int n)
- : bytes(bytes), y(y), paint(paint), n(n) {}
- size_t bytes;
- SkScalar y;
- SkPaint paint;
- int n;
- void draw(SkCanvas* c, const SkMatrix&) const {
- auto xs = pod<SkScalar>(this);
- auto text = pod<void>(this, n * sizeof(SkScalar));
- c->drawPosTextH(text, bytes, xs, y, paint);
- }
-};
-struct DrawTextRSXform final : Op {
- static const auto kType = Type::DrawTextRSXform;
- DrawTextRSXform(size_t bytes, int xforms, const SkRect* cull, const SkPaint& paint)
- : bytes(bytes), xforms(xforms), paint(paint) {
- if (cull) {
- this->cull = *cull;
- }
- }
- size_t bytes;
- int xforms;
- SkRect cull = kUnset;
- SkPaint paint;
- void draw(SkCanvas* c, const SkMatrix&) const {
- // For alignment, the SkRSXforms are first in the pod section, followed by the text.
- c->drawTextRSXform(pod<void>(this, xforms * sizeof(SkRSXform)), bytes, pod<SkRSXform>(this),
- maybe_unset(cull), paint);
- }
-};
struct DrawTextBlob final : Op {
static const auto kType = Type::DrawTextBlob;
DrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint)
@@ -579,6 +535,10 @@ void DisplayListData::saveLayer(const SkRect* bounds, const SkPaint* paint,
this->push<SaveLayer>(0, bounds, paint, backdrop, clipMask, clipMatrix, flags);
}
+void DisplayListData::saveBehind(const SkRect* subset) {
+ this->push<SaveBehind>(0, subset);
+}
+
void DisplayListData::concat(const SkMatrix& matrix) {
this->push<Concat>(0, matrix);
}
@@ -667,33 +627,6 @@ void DisplayListData::drawImageLattice(sk_sp<const SkImage> image, const SkCanva
fs);
}
-void DisplayListData::drawText(const void* text, size_t bytes, SkScalar x, SkScalar y,
- const SkPaint& paint) {
- void* pod = this->push<DrawText>(bytes, bytes, x, y, paint);
- copy_v(pod, (const char*)text, bytes);
- mHasText = true;
-}
-void DisplayListData::drawPosText(const void* text, size_t bytes, const SkPoint pos[],
- const SkPaint& paint) {
- int n = paint.countText(text, bytes);
- void* pod = this->push<DrawPosText>(n * sizeof(SkPoint) + bytes, bytes, paint, n);
- copy_v(pod, pos, n, (const char*)text, bytes);
- mHasText = true;
-}
-void DisplayListData::drawPosTextH(const void* text, size_t bytes, const SkScalar xs[], SkScalar y,
- const SkPaint& paint) {
- int n = paint.countText(text, bytes);
- void* pod = this->push<DrawPosTextH>(n * sizeof(SkScalar) + bytes, bytes, y, paint, n);
- copy_v(pod, xs, n, (const char*)text, bytes);
- mHasText = true;
-}
-void DisplayListData::drawTextRSXform(const void* text, size_t bytes, const SkRSXform xforms[],
- const SkRect* cull, const SkPaint& paint) {
- int n = paint.countText(text, bytes);
- void* pod = this->push<DrawTextRSXform>(bytes + n * sizeof(SkRSXform), bytes, n, cull, paint);
- copy_v(pod, xforms, n, (const char*)text, bytes);
- mHasText = true;
-}
void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) {
this->push<DrawTextBlob>(0, blob, x, y, paint);
@@ -848,6 +781,11 @@ void RecordingCanvas::willRestore() {
fDL->restore();
}
+bool RecordingCanvas::onDoSaveBehind(const SkRect* subset) {
+ fDL->saveBehind(subset);
+ return false;
+}
+
void RecordingCanvas::didConcat(const SkMatrix& matrix) {
fDL->concat(matrix);
}
@@ -912,22 +850,6 @@ void RecordingCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkD
fDL->drawAnnotation(rect, key, val);
}
-void RecordingCanvas::onDrawText(const void* text, size_t bytes, SkScalar x, SkScalar y,
- const SkPaint& paint) {
- fDL->drawText(text, bytes, x, y, paint);
-}
-void RecordingCanvas::onDrawPosText(const void* text, size_t bytes, const SkPoint pos[],
- const SkPaint& paint) {
- fDL->drawPosText(text, bytes, pos, paint);
-}
-void RecordingCanvas::onDrawPosTextH(const void* text, size_t bytes, const SkScalar xs[],
- SkScalar y, const SkPaint& paint) {
- fDL->drawPosTextH(text, bytes, xs, y, paint);
-}
-void RecordingCanvas::onDrawTextRSXform(const void* text, size_t bytes, const SkRSXform xform[],
- const SkRect* cull, const SkPaint& paint) {
- fDL->drawTextRSXform(text, bytes, xform, cull, paint);
-}
void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) {
fDL->drawTextBlob(blob, x, y, paint);
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 08cfc6266f56..caaef67f724f 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -65,6 +65,7 @@ public:
void applyColorTransform(ColorTransform transform);
bool hasText() const { return mHasText; }
+ size_t usedSize() const { return fUsed; }
private:
friend class RecordingCanvas;
@@ -74,6 +75,7 @@ private:
void save();
void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, const SkImage*,
const SkMatrix*, SkCanvas::SaveLayerFlags);
+ void saveBehind(const SkRect*);
void restore();
void concat(const SkMatrix&);
@@ -99,10 +101,6 @@ private:
void drawDrawable(SkDrawable*, const SkMatrix*);
void drawPicture(const SkPicture*, const SkMatrix*, const SkPaint*);
- void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&);
- void drawPosText(const void*, size_t, const SkPoint[], const SkPaint&);
- void drawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&);
- void drawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&);
void drawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&);
void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkPaint*, BitmapPalette palette);
@@ -145,6 +143,7 @@ public:
void willSave() override;
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
void willRestore() override;
+ bool onDoSaveBehind(const SkRect*) override;
void onFlush() override;
@@ -170,12 +169,6 @@ public:
void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
- void onDrawText(const void*, size_t, SkScalar x, SkScalar y, const SkPaint&) override;
- void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override;
- void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override;
-
- void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*,
- const SkPaint&) override;
void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override;
void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override;
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index d6362ef10aad..24443c8c9836 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -57,15 +57,15 @@ public:
inline Rect(float width, float height) : left(0.0f), top(0.0f), right(width), bottom(height) {}
- inline Rect(const SkIRect& rect)
- : // NOLINT, implicit
+ inline Rect(const SkIRect& rect) // NOLINT(google-explicit-constructor)
+ :
left(rect.fLeft)
, top(rect.fTop)
, right(rect.fRight)
, bottom(rect.fBottom) {}
- inline Rect(const SkRect& rect)
- : // NOLINT, implicit
+ inline Rect(const SkRect& rect) // NOLINT(google-explicit-constructor)
+ :
left(rect.fLeft)
, top(rect.fTop)
, right(rect.fRight)
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 4a639102192f..1ff7ffe6bf87 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -288,7 +288,10 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
mDisplayList = mStagingDisplayList;
mStagingDisplayList = nullptr;
if (mDisplayList) {
- mDisplayList->syncContents();
+ WebViewSyncData syncData {
+ .applyForceDark = info && !info->disableForceDark
+ };
+ mDisplayList->syncContents(syncData);
handleForceDark(info);
}
}
@@ -454,6 +457,9 @@ const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const {
using StringBuffer = FatVector<char, 128>;
template <typename... T>
+// TODO:__printflike(2, 3)
+// Doesn't work because the warning doesn't understand string_view and doesn't like that
+// it's not a C-style variadic function.
static void format(StringBuffer& buffer, const std::string_view& format, T... args) {
buffer.resize(buffer.capacity());
while (1) {
@@ -468,19 +474,20 @@ static void format(StringBuffer& buffer, const std::string_view& format, T... ar
buffer.resize(needed + 1);
return;
}
- buffer.resize(buffer.size() * 2);
+ // If we're doing a heap alloc anyway might as well give it some slop
+ buffer.resize(needed + 100);
}
}
void RenderNode::markDrawStart(SkCanvas& canvas) {
StringBuffer buffer;
- format(buffer, "RenderNode(id=%d, name='%s')", uniqueId(), getName());
+ format(buffer, "RenderNode(id=%" PRId64 ", name='%s')", uniqueId(), getName());
canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr);
}
void RenderNode::markDrawEnd(SkCanvas& canvas) {
StringBuffer buffer;
- format(buffer, "/RenderNode(id=%d, name='%s')", uniqueId(), getName());
+ format(buffer, "/RenderNode(id=%" PRId64 ", name='%s')", uniqueId(), getName());
canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr);
}
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 04379ae68a0d..ddb7e4e4ce74 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -98,15 +98,15 @@ public:
LayerProperties& operator=(const LayerProperties& other);
+ // Strongly recommend using effectiveLayerType instead
+ LayerType type() const { return mType; }
+
private:
LayerProperties();
~LayerProperties();
void reset();
bool setColorFilter(SkColorFilter* filter);
- // Private since external users should go through properties().effectiveLayerType()
- LayerType type() const { return mType; }
-
friend class RenderProperties;
LayerType mType = LayerType::None;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index ba343841d760..cc62fdc76ef8 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -24,6 +24,7 @@
#include "hwui/PaintFilter.h"
#include "pipeline/skia/AnimatedDrawables.h"
+#include <SkAndroidFrameworkUtils.h>
#include <SkAnimatedImage.h>
#include <SkCanvasStateUtils.h>
#include <SkColorFilter.h>
@@ -185,6 +186,11 @@ int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
return this->saveLayer(left, top, right, bottom, nullptr, flags);
}
+int SkiaCanvas::saveUnclippedLayer(int left, int top, int right, int bottom) {
+ SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
+ return SkAndroidFrameworkUtils::SaveBehind(mCanvas, &bounds);
+}
+
class SkiaCanvas::Clip {
public:
Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m)
@@ -672,16 +678,16 @@ void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
// Canvas draw operations: Text
// ----------------------------------------------------------------------------
-void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
+void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x,
float y, float boundsLeft, float boundsTop, float boundsRight,
float boundsBottom, float totalAdvance) {
if (count <= 0 || paint.nothingToDraw()) return;
- SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
SkPaint paintCopy(paint);
if (mPaintFilter) {
mPaintFilter->filter(&paintCopy);
}
- SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
+ SkFont font = SkFont::LEGACY_ExtractFromPaint(paintCopy);
+ SkASSERT(paintCopy.getTextEncoding() == kGlyphID_SkTextEncoding);
// Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and
// older.
if (!mCanvasOwned && sApiLevel <= 27 && paintCopy.getStrokeWidth() <= 0 &&
@@ -702,18 +708,20 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p
}
void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start,
+ const Paint& paint, const SkPath& path, size_t start,
size_t end) {
SkPaint paintCopy(paint);
if (mPaintFilter) {
mPaintFilter->filter(&paintCopy);
}
- SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
+ SkFont font = SkFont::LEGACY_ExtractFromPaint(paintCopy);
+ SkASSERT(paintCopy.getTextEncoding() == kGlyphID_SkTextEncoding);
const int N = end - start;
- SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
- SkRSXform* xform = (SkRSXform*)storage.get();
- uint16_t* glyphs = (uint16_t*)(xform + N);
+ SkTextBlobBuilder builder;
+ auto rec = builder.allocRunRSXform(font, N);
+ SkRSXform* xform = (SkRSXform*)rec.pos;
+ uint16_t* glyphs = rec.glyphs;
SkPathMeasure meas(path, false);
for (size_t i = start; i < end; i++) {
@@ -734,7 +742,7 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,
xform[i - start].fTy = pos.y() + tan.x() * y - halfWidth * tan.y();
}
- this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paintCopy);
+ this->asSkCanvas()->drawTextBlob(builder.make(), 0, 0, paintCopy);
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 24d9c08ec1c6..3fe2bce06b41 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -74,6 +74,7 @@ public:
SaveFlags::Flags flags) override;
virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
SaveFlags::Flags flags) override;
+ virtual int saveUnclippedLayer(int left, int top, int right, int bottom) override;
virtual void getMatrix(SkMatrix* outMatrix) const override;
virtual void setMatrix(const SkMatrix& matrix) override;
@@ -157,11 +158,11 @@ protected:
void reset(SkCanvas* skiaCanvas);
void drawDrawable(SkDrawable* drawable) { mCanvas->drawDrawable(drawable); }
- virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
+ virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x,
float y, float boundsLeft, float boundsTop, float boundsRight,
float boundsBottom, float totalAdvance) override;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start,
+ const Paint& paint, const SkPath& path, size_t start,
size_t end) override;
/** This class acts as a copy on write SkPaint.
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
new file mode 100644
index 000000000000..9170d6d1dc50
--- /dev/null
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+#include "WebViewFunctorManager.h"
+
+#include <private/hwui/WebViewFunctor.h>
+#include "Properties.h"
+#include "renderthread/RenderThread.h"
+
+#include <log/log.h>
+#include <utils/Trace.h>
+#include <atomic>
+
+namespace android::uirenderer {
+
+RenderMode WebViewFunctor_queryPlatformRenderMode() {
+ auto pipelineType = Properties::getRenderPipelineType();
+ switch (pipelineType) {
+ case RenderPipelineType::SkiaGL:
+ return RenderMode::OpenGL_ES;
+ case RenderPipelineType::SkiaVulkan:
+ return RenderMode::Vulkan;
+ default:
+ LOG_ALWAYS_FATAL("Unknown render pipeline type: %d", (int)pipelineType);
+ }
+}
+
+int WebViewFunctor_create(void* data, const WebViewFunctorCallbacks& prototype,
+ RenderMode functorMode) {
+ if (functorMode != RenderMode::OpenGL_ES && functorMode != RenderMode::Vulkan) {
+ ALOGW("Unknown rendermode %d", (int)functorMode);
+ return -1;
+ }
+ if (functorMode == RenderMode::Vulkan &&
+ WebViewFunctor_queryPlatformRenderMode() != RenderMode::Vulkan) {
+ ALOGW("Unable to map from GLES platform to a vulkan functor");
+ return -1;
+ }
+ return WebViewFunctorManager::instance().createFunctor(data, prototype, functorMode);
+}
+
+void WebViewFunctor_release(int functor) {
+ WebViewFunctorManager::instance().releaseFunctor(functor);
+}
+
+static std::atomic_int sNextId{1};
+
+WebViewFunctor::WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
+ RenderMode functorMode)
+ : mData(data) {
+ mFunctor = sNextId++;
+ mCallbacks = callbacks;
+ mMode = functorMode;
+}
+
+WebViewFunctor::~WebViewFunctor() {
+ destroyContext();
+
+ ATRACE_NAME("WebViewFunctor::onDestroy");
+ mCallbacks.onDestroyed(mFunctor, mData);
+}
+
+void WebViewFunctor::sync(const WebViewSyncData& syncData) const {
+ ATRACE_NAME("WebViewFunctor::sync");
+ mCallbacks.onSync(mFunctor, mData, syncData);
+}
+
+void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
+ ATRACE_NAME("WebViewFunctor::drawGl");
+ if (!mHasContext) {
+ mHasContext = true;
+ }
+ mCallbacks.gles.draw(mFunctor, mData, drawInfo);
+}
+
+void WebViewFunctor::destroyContext() {
+ if (mHasContext) {
+ mHasContext = false;
+ ATRACE_NAME("WebViewFunctor::onContextDestroyed");
+ mCallbacks.onContextDestroyed(mFunctor, mData);
+
+ // grContext may be null in unit tests.
+ auto* grContext = renderthread::RenderThread::getInstance().getGrContext();
+ if (grContext) grContext->resetContext();
+ }
+}
+
+WebViewFunctorManager& WebViewFunctorManager::instance() {
+ static WebViewFunctorManager sInstance;
+ return sInstance;
+}
+
+int WebViewFunctorManager::createFunctor(void* data, const WebViewFunctorCallbacks& callbacks,
+ RenderMode functorMode) {
+ auto object = std::make_unique<WebViewFunctor>(data, callbacks, functorMode);
+ int id = object->id();
+ auto handle = object->createHandle();
+ {
+ std::lock_guard _lock{mLock};
+ mActiveFunctors.push_back(std::move(handle));
+ mFunctors.push_back(std::move(object));
+ }
+ return id;
+}
+
+void WebViewFunctorManager::releaseFunctor(int functor) {
+ sp<WebViewFunctor::Handle> toRelease;
+ {
+ std::lock_guard _lock{mLock};
+ for (auto iter = mActiveFunctors.begin(); iter != mActiveFunctors.end(); iter++) {
+ if ((*iter)->id() == functor) {
+ toRelease = std::move(*iter);
+ mActiveFunctors.erase(iter);
+ break;
+ }
+ }
+ }
+}
+
+void WebViewFunctorManager::onContextDestroyed() {
+ // WARNING: SKETCHY
+ // Because we know that we always remove from mFunctors on RenderThread, the same
+ // thread that always invokes onContextDestroyed, we know that the functor pointers
+ // will remain valid without the lock held.
+ // However, we won't block new functors from being added in the meantime.
+ mLock.lock();
+ const size_t size = mFunctors.size();
+ WebViewFunctor* toDestroyContext[size];
+ for (size_t i = 0; i < size; i++) {
+ toDestroyContext[i] = mFunctors[i].get();
+ }
+ mLock.unlock();
+ for (size_t i = 0; i < size; i++) {
+ toDestroyContext[i]->destroyContext();
+ }
+}
+
+void WebViewFunctorManager::destroyFunctor(int functor) {
+ std::unique_ptr<WebViewFunctor> toRelease;
+ {
+ std::lock_guard _lock{mLock};
+ for (auto iter = mFunctors.begin(); iter != mFunctors.end(); iter++) {
+ if ((*iter)->id() == functor) {
+ toRelease = std::move(*iter);
+ mFunctors.erase(iter);
+ break;
+ }
+ }
+ }
+}
+
+sp<WebViewFunctor::Handle> WebViewFunctorManager::handleFor(int functor) {
+ std::lock_guard _lock{mLock};
+ for (auto& iter : mActiveFunctors) {
+ if (iter->id() == functor) {
+ return iter;
+ }
+ }
+ return nullptr;
+}
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h
new file mode 100644
index 000000000000..1719ce7cca75
--- /dev/null
+++ b/libs/hwui/WebViewFunctorManager.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <private/hwui/WebViewFunctor.h>
+#include <renderthread/RenderProxy.h>
+
+#include <utils/LightRefBase.h>
+#include <mutex>
+#include <vector>
+
+namespace android::uirenderer {
+
+class WebViewFunctorManager;
+
+class WebViewFunctor {
+public:
+ WebViewFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
+ ~WebViewFunctor();
+
+ class Handle : public LightRefBase<Handle> {
+ public:
+ ~Handle() { renderthread::RenderProxy::destroyFunctor(id()); }
+
+ int id() const { return mReference.id(); }
+
+ void sync(const WebViewSyncData& syncData) const { mReference.sync(syncData); }
+
+ void drawGl(const DrawGlInfo& drawInfo) const { mReference.drawGl(drawInfo); }
+
+ private:
+ friend class WebViewFunctor;
+
+ Handle(WebViewFunctor& ref) : mReference(ref) {}
+
+ WebViewFunctor& mReference;
+ };
+
+ int id() const { return mFunctor; }
+ void sync(const WebViewSyncData& syncData) const;
+ void drawGl(const DrawGlInfo& drawInfo);
+ void destroyContext();
+
+ sp<Handle> createHandle() {
+ LOG_ALWAYS_FATAL_IF(mCreatedHandle);
+ mCreatedHandle = true;
+ return sp<Handle>{new Handle(*this)};
+ }
+
+private:
+ WebViewFunctorCallbacks mCallbacks;
+ void* const mData;
+ int mFunctor;
+ RenderMode mMode;
+ bool mHasContext = false;
+ bool mCreatedHandle = false;
+};
+
+class WebViewFunctorManager {
+public:
+ static WebViewFunctorManager& instance();
+
+ int createFunctor(void* data, const WebViewFunctorCallbacks& callbacks, RenderMode functorMode);
+ void releaseFunctor(int functor);
+ void onContextDestroyed();
+ void destroyFunctor(int functor);
+
+ sp<WebViewFunctor::Handle> handleFor(int functor);
+
+private:
+ WebViewFunctorManager() = default;
+ ~WebViewFunctorManager() = default;
+
+ std::mutex mLock;
+ std::vector<std::unique_ptr<WebViewFunctor>> mFunctors;
+ std::vector<sp<WebViewFunctor::Handle>> mActiveFunctors;
+};
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/debug/GlesErrorCheckWrapper.h b/libs/hwui/debug/GlesErrorCheckWrapper.h
index ee5cc1f46de8..791400bf30ec 100644
--- a/libs/hwui/debug/GlesErrorCheckWrapper.h
+++ b/libs/hwui/debug/GlesErrorCheckWrapper.h
@@ -24,7 +24,7 @@ namespace debug {
class GlesErrorCheckWrapper : public GlesDriver {
public:
- GlesErrorCheckWrapper(GlesDriver& base) : mBase(base) {}
+ explicit GlesErrorCheckWrapper(GlesDriver& base) : mBase(base) {}
#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override;
#include "gles_decls.in"
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 6c77f9ee1845..6e0258c9ecb2 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -75,20 +75,33 @@ sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
}
-static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
- void* addr = calloc(size, 1);
- if (!addr) {
+sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
+ // Create new ashmem region with read/write priv
+ int fd = ashmem_create_region("bitmap", size);
+ if (fd < 0) {
return nullptr;
}
- return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
+
+ void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED) {
+ close(fd);
+ return nullptr;
+ }
+
+ if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
+ munmap(addr, size);
+ close(fd);
+ return nullptr;
+ }
+ return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
}
-sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) {
+sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
}
sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
- return allocateBitmap(bitmap, &android::allocateHeapBitmap);
+ return allocateBitmap(bitmap, &Bitmap::allocateHeapBitmap);
}
sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
@@ -97,28 +110,15 @@ sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
return nullptr;
}
- return android::allocateHeapBitmap(size, info, info.minRowBytes());
+ return allocateHeapBitmap(size, info, info.minRowBytes());
}
-sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
- // Create new ashmem region with read/write priv
- int fd = ashmem_create_region("bitmap", size);
- if (fd < 0) {
- return nullptr;
- }
-
- void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (addr == MAP_FAILED) {
- close(fd);
- return nullptr;
- }
-
- if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
- munmap(addr, size);
- close(fd);
+sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
+ void* addr = calloc(size, 1);
+ if (!addr) {
return nullptr;
}
- return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
+ return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
}
void FreePixelRef(void* addr, void* context) {
@@ -132,17 +132,38 @@ sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef)
pixelRef.rowBytes()));
}
-sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
- return createFrom(graphicBuffer, SkColorSpace::MakeSRGB());
-}
-sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, sk_sp<SkColorSpace> colorSpace) {
+sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, sk_sp<SkColorSpace> colorSpace,
+ SkAlphaType alphaType, BitmapPalette palette) {
// As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can
- // view the colorspace as RGBA8888.
+ // view the format as RGBA8888.
SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType,
- colorSpace);
- return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
+ kRGBA_8888_SkColorType, alphaType, colorSpace);
+ return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info, palette));
+}
+
+sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr,
+ size_t size, bool readOnly) {
+ if (info.colorType() == kUnknown_SkColorType) {
+ LOG_ALWAYS_FATAL("unknown bitmap configuration");
+ return nullptr;
+ }
+
+ if (!addr) {
+ // Map existing ashmem region if not already mapped.
+ int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
+ size = ashmem_get_size_region(fd);
+ addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED) {
+ return nullptr;
+ }
+ }
+
+ sk_sp<Bitmap> bitmap(new Bitmap(addr, fd, size, info, rowBytes));
+ if (readOnly) {
+ bitmap->setImmutable();
+ }
+ return bitmap;
}
void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index d446377ec1d9..2138040d9690 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -54,28 +54,31 @@ typedef void (*FreeFunc)(void* addr, void* context);
class ANDROID_API Bitmap : public SkPixelRef {
public:
+ /* The allocate factories not only construct the Bitmap object but also allocate the
+ * backing store whose type is determined by the specific method that is called.
+ *
+ * The factories that accept SkBitmap* as a param will modify those params by
+ * installing the returned bitmap as their SkPixelRef.
+ *
+ * The factories that accept const SkBitmap& as a param will copy the contents of the
+ * provided bitmap into the newly allocated buffer.
+ */
+ static sk_sp<Bitmap> allocateAshmemBitmap(SkBitmap* bitmap);
+ static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& bitmap);
static sk_sp<Bitmap> allocateHeapBitmap(SkBitmap* bitmap);
static sk_sp<Bitmap> allocateHeapBitmap(const SkImageInfo& info);
- static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
-
- static sk_sp<Bitmap> allocateAshmemBitmap(SkBitmap* bitmap);
- static sk_sp<Bitmap> allocateAshmemBitmap(size_t allocSize, const SkImageInfo& info,
- size_t rowBytes);
-
- static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer);
+ /* The createFrom factories construct a new Bitmap object by wrapping the already allocated
+ * memory that is provided as an input param.
+ */
static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer,
- sk_sp<SkColorSpace> colorSpace);
-
+ sk_sp<SkColorSpace> colorSpace,
+ SkAlphaType alphaType = kPremul_SkAlphaType,
+ BitmapPalette palette = BitmapPalette::Unknown);
+ static sk_sp<Bitmap> createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr,
+ size_t size, bool readOnly);
static sk_sp<Bitmap> createFrom(const SkImageInfo&, SkPixelRef&);
- Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes);
- Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
- size_t rowBytes);
- Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes);
- Bitmap(GraphicBuffer* buffer, const SkImageInfo& info,
- BitmapPalette palette = BitmapPalette::Unknown);
-
int rowBytesAsPixels() const { return rowBytes() >> mInfo.shiftPerPixel(); }
void reconfigure(const SkImageInfo& info, size_t rowBytes);
@@ -123,6 +126,15 @@ public:
}
private:
+ static sk_sp<Bitmap> allocateAshmemBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);
+ static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes);
+
+ Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes);
+ Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
+ size_t rowBytes);
+ Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes);
+ Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette);
+
virtual ~Bitmap();
void* getStorage() const;
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index e2ea2bc37375..277148e3d556 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -38,7 +38,7 @@ static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkSca
canvas->drawRect(left, top, right, bottom, paint);
}
-void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) {
+void Canvas::drawTextDecorations(float x, float y, float length, const Paint& paint) {
uint32_t flags;
PaintFilter* paintFilter = getPaintFilter();
if (paintFilter) {
@@ -52,7 +52,7 @@ void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint&
const SkScalar left = x;
const SkScalar right = x + length;
if (flags & SkPaint::kUnderlineText_ReserveFlag) {
- Paint::FontMetrics metrics;
+ SkFontMetrics metrics;
paint.getFontMetrics(&metrics);
SkScalar position;
if (!metrics.hasUnderlinePosition(&position)) {
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index a5f21d8e6d73..11e8579a481f 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -178,6 +178,9 @@ public:
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
virtual void callDrawGLFunction(Functor* functor,
uirenderer::GlFunctorLifecycleListener* listener) = 0;
+ virtual void drawWebViewFunctor(int /*functor*/) {
+ LOG_ALWAYS_FATAL("Not supported");
+ }
// ----------------------------------------------------------------------------
// Canvas state operations
@@ -193,6 +196,7 @@ public:
SaveFlags::Flags flags) = 0;
virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
SaveFlags::Flags flags) = 0;
+ virtual int saveUnclippedLayer(int, int, int, int) = 0;
// Matrix
virtual void getMatrix(SkMatrix* outMatrix) const = 0;
@@ -299,18 +303,18 @@ public:
static int GetApiLevel() { return sApiLevel; }
protected:
- void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
+ void drawTextDecorations(float x, float y, float length, const Paint& paint);
/**
* glyphFunc: valid only for the duration of the call and should not be cached.
* drawText: count is of glyphs
* totalAdvance: used to define width of text decorations (underlines, strikethroughs).
*/
- virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
+ virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x,
float y, float boundsLeft, float boundsTop, float boundsRight,
float boundsBottom, float totalAdvance) = 0;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start,
+ const Paint& paint, const SkPath& path, size_t start,
size_t end) = 0;
static int sApiLevel;
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 769fce498a70..84292c8768c1 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -43,7 +43,7 @@ MinikinFontSkia::MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontDat
static void MinikinFontSkia_SetSkiaPaint(const minikin::MinikinFont* font, SkPaint* skPaint,
const minikin::MinikinPaint& paint,
const minikin::FontFakery& fakery) {
- skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ skPaint->setTextEncoding(kGlyphID_SkTextEncoding);
skPaint->setTextSize(paint.size);
skPaint->setTextScaleX(paint.scaleX);
skPaint->setTextSkewX(paint.skewX);
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index c1a3b6d1143b..92ffda9486bb 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -46,7 +46,7 @@ public:
Paint();
Paint(const Paint& paint);
- Paint(const SkPaint& paint); // NOLINT(implicit)
+ Paint(const SkPaint& paint); // NOLINT(google-explicit-constructor)
~Paint();
Paint& operator=(const Paint& other);
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index 206219426bb0..0eb526af127a 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -82,23 +82,6 @@ protected:
mOutput << mIdent << "drawDRRect" << std::endl;
}
- void onDrawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {
- mOutput << mIdent << "drawText" << std::endl;
- }
-
- void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override {
- mOutput << mIdent << "drawPosText" << std::endl;
- }
-
- void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override {
- mOutput << mIdent << "drawPosTextH" << std::endl;
- }
-
- void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*,
- const SkPaint&) override {
- mOutput << mIdent << "drawTextRSXform" << std::endl;
- }
-
void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override {
mOutput << mIdent << "drawTextBlob" << std::endl;
}
diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h
index af3a056864a7..cf2f93b95e71 100644
--- a/libs/hwui/pipeline/skia/FunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/FunctorDrawable.h
@@ -21,7 +21,9 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
+#include <WebViewFunctorManager.h>
#include <utils/Functor.h>
+#include <variant>
namespace android {
namespace uirenderer {
@@ -35,17 +37,43 @@ namespace skiapipeline {
class FunctorDrawable : public SkDrawable {
public:
FunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
- : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {}
+ : mBounds(canvas->getLocalClipBounds())
+ , mAnyFunctor(std::in_place_type<LegacyFunctor>, functor, listener) {}
+
+ FunctorDrawable(int functor, SkCanvas* canvas)
+ : mBounds(canvas->getLocalClipBounds())
+ , mAnyFunctor(std::in_place_type<NewFunctor>, functor) {}
+
virtual ~FunctorDrawable() {}
- virtual void syncFunctor() const = 0;
+ virtual void syncFunctor(const WebViewSyncData& data) const {
+ if (mAnyFunctor.index() == 0) {
+ std::get<0>(mAnyFunctor).handle->sync(data);
+ } else {
+ (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeSync, nullptr);
+ }
+ }
protected:
virtual SkRect onGetBounds() override { return mBounds; }
- Functor* mFunctor;
- sp<GlFunctorLifecycleListener> mListener;
const SkRect mBounds;
+
+ struct LegacyFunctor {
+ explicit LegacyFunctor(Functor* functor, GlFunctorLifecycleListener* listener)
+ : functor(functor), listener(listener) {}
+ Functor* functor;
+ sp<GlFunctorLifecycleListener> listener;
+ };
+
+ struct NewFunctor {
+ explicit NewFunctor(int functor) {
+ handle = WebViewFunctorManager::instance().handleFor(functor);
+ }
+ sp<WebViewFunctor::Handle> handle;
+ };
+
+ std::variant<NewFunctor, LegacyFunctor> mAnyFunctor;
};
} // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 4a87e7502c6f..240efb41285c 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -17,29 +17,28 @@
#include "GLFunctorDrawable.h"
#include <GrContext.h>
#include <private/hwui/DrawGlInfo.h>
+#include "FunctorDrawable.h"
#include "GlFunctorLifecycleListener.h"
+#include "GrBackendSurface.h"
+#include "GrRenderTarget.h"
+#include "GrRenderTargetContext.h"
#include "RenderNode.h"
#include "SkAndroidFrameworkUtils.h"
#include "SkClipStack.h"
#include "SkRect.h"
-#include "GrBackendSurface.h"
-#include "GrRenderTarget.h"
-#include "GrRenderTargetContext.h"
namespace android {
namespace uirenderer {
namespace skiapipeline {
GLFunctorDrawable::~GLFunctorDrawable() {
- if (mListener.get() != nullptr) {
- mListener->onGlFunctorReleased(mFunctor);
+ if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
+ if (lp->listener) {
+ lp->listener->onGlFunctorReleased(lp->functor);
+ }
}
}
-void GLFunctorDrawable::syncFunctor() const {
- (*mFunctor)(DrawGlInfo::kModeSync, nullptr);
-}
-
static void setScissor(int viewportHeight, const SkIRect& clip) {
SkASSERT(!clip.isEmpty());
// transform to Y-flipped GL space, and prevent negatives
@@ -49,14 +48,14 @@ static void setScissor(int viewportHeight, const SkIRect& clip) {
}
static bool GetFboDetails(SkCanvas* canvas, GLuint* outFboID, SkISize* outFboSize) {
- GrRenderTargetContext *renderTargetContext =
+ GrRenderTargetContext* renderTargetContext =
canvas->internal_private_accessTopLayerRenderTargetContext();
if (!renderTargetContext) {
ALOGW("Unable to extract renderTarget info from canvas; aborting GLFunctor draw");
return false;
}
- GrRenderTarget *renderTarget = renderTargetContext->accessRenderTarget();
+ GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget();
if (!renderTarget) {
ALOGW("Unable to extract renderTarget info from canvas; aborting GLFunctor draw");
return false;
@@ -94,16 +93,16 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
sk_sp<SkSurface> tmpSurface;
// we are in a state where there is an unclipped saveLayer
if (fboID != 0 && !surfaceBounds.contains(clipBounds)) {
-
// create an offscreen layer and clear it
- SkImageInfo surfaceInfo = canvas->imageInfo().makeWH(clipBounds.width(), clipBounds.height());
- tmpSurface = SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kYes,
- surfaceInfo);
+ SkImageInfo surfaceInfo =
+ canvas->imageInfo().makeWH(clipBounds.width(), clipBounds.height());
+ tmpSurface =
+ SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kYes, surfaceInfo);
tmpSurface->getCanvas()->clear(SK_ColorTRANSPARENT);
GrGLFramebufferInfo fboInfo;
if (!tmpSurface->getBackendRenderTarget(SkSurface::kFlushWrite_BackendHandleAccess)
- .getGLFramebufferInfo(&fboInfo)) {
+ .getGLFramebufferInfo(&fboInfo)) {
ALOGW("Unable to extract renderTarget info from offscreen canvas; aborting GLFunctor");
return;
}
@@ -144,7 +143,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
bool clearStencilAfterFunctor = false;
if (CC_UNLIKELY(clipRegion.isComplex())) {
// clear the stencil
- //TODO: move stencil clear and canvas flush to SkAndroidFrameworkUtils::clipWithStencil
+ // TODO: move stencil clear and canvas flush to SkAndroidFrameworkUtils::clipWithStencil
glDisable(GL_SCISSOR_TEST);
glStencilMask(0x1);
glClearStencil(0);
@@ -163,7 +162,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
// GL ops get inserted here if previous flush is missing, which could dirty the stencil
bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(tmpCanvas);
- tmpCanvas->flush(); //need this flush for the single op that draws into the stencil
+ tmpCanvas->flush(); // need this flush for the single op that draws into the stencil
// ensure that the framebuffer that the webview will render into is bound before after we
// draw into the stencil
@@ -188,7 +187,11 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
setScissor(info.height, clipRegion.getBounds());
}
- (*mFunctor)(DrawGlInfo::kModeDraw, &info);
+ if (mAnyFunctor.index() == 0) {
+ std::get<0>(mAnyFunctor).handle->drawGl(info);
+ } else {
+ (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info);
+ }
if (clearStencilAfterFunctor) {
// clear stencil buffer as it may be used by Skia
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
index 215979cba2e3..2ea4f67428bc 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
@@ -31,11 +31,9 @@ namespace skiapipeline {
*/
class GLFunctorDrawable : public FunctorDrawable {
public:
- GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
- : FunctorDrawable(functor, listener, canvas) {}
- virtual ~GLFunctorDrawable();
+ using FunctorDrawable::FunctorDrawable;
- void syncFunctor() const override;
+ virtual ~GLFunctorDrawable();
protected:
void onDraw(SkCanvas* canvas) override;
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index f08ac17e4082..eed19420a78a 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <utils/MathUtils.h>
#include "LayerDrawable.h"
+#include <utils/MathUtils.h>
#include "GrBackendSurface.h"
#include "SkColorFilter.h"
@@ -44,10 +44,9 @@ static bool shouldFilter(const SkMatrix& matrix) {
if (!matrix.isScaleTranslate()) return true;
// We only care about meaningful scale here
- bool noScale = MathUtils::isOne(matrix.getScaleX())
- && MathUtils::isOne(matrix.getScaleY());
- bool pixelAligned = SkScalarIsInt(matrix.getTranslateX())
- && SkScalarIsInt(matrix.getTranslateY());
+ bool noScale = MathUtils::isOne(matrix.getScaleX()) && MathUtils::isOne(matrix.getScaleY());
+ bool pixelAligned =
+ SkScalarIsInt(matrix.getTranslateX()) && SkScalarIsInt(matrix.getTranslateY());
return !(noScale && pixelAligned);
}
@@ -120,11 +119,12 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
// Integer translation is defined as when src rect and dst rect align fractionally.
// Skia TextureOp has the above logic build-in, but not NonAAFillRectOp. TextureOp works
// only for SrcOver blending and without color filter (readback uses Src blending).
- bool isIntegerTranslate = isBasicallyTranslate(totalMatrix)
- && SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX])
- == SkScalarFraction(skiaSrcRect.fLeft)
- && SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY])
- == SkScalarFraction(skiaSrcRect.fTop);
+ bool isIntegerTranslate =
+ isBasicallyTranslate(totalMatrix) &&
+ SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX]) ==
+ SkScalarFraction(skiaSrcRect.fLeft) &&
+ SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY]) ==
+ SkScalarFraction(skiaSrcRect.fTop);
if (layer->getForceFilter() || !isIntegerTranslate) {
paint.setFilterQuality(kLow_SkFilterQuality);
}
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index 95dc6d0cf096..7cd515ae9fcb 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -32,8 +32,8 @@ class LayerDrawable : public SkDrawable {
public:
explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {}
- static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
- const SkRect* srcRect, const SkRect* dstRect, bool useLayerTransform);
+ static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, const SkRect* srcRect,
+ const SkRect* dstRect, bool useLayerTransform);
protected:
virtual SkRect onGetBounds() override {
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 4494cb05df10..df1537e2d824 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -127,6 +127,7 @@ public:
mNode.markDrawEnd(mCanvas);
}
}
+
private:
SkCanvas& mCanvas;
RenderNode& mNode;
@@ -140,7 +141,7 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) {
// ensures that we paint the layer even if it is not currently visible in the
// event that the properties change and it becomes visible.
if ((mProjectedDisplayList == nullptr && !renderNode->isRenderable()) ||
- (renderNode->nothingToDraw() && mComposeLayer)) {
+ (renderNode->nothingToDraw() && mComposeLayer)) {
return;
}
@@ -234,8 +235,8 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
// we need to restrict the portion of the surface drawn to the size of the renderNode.
SkASSERT(renderNode->getLayerSurface()->width() >= bounds.width());
SkASSERT(renderNode->getLayerSurface()->height() >= bounds.height());
- canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(),
- bounds, bounds, &paint);
+ canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(), bounds,
+ bounds, &paint);
if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 073b4814305e..562a3b225e36 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -15,11 +15,11 @@
*/
#include "ShaderCache.h"
-#include <algorithm>
#include <log/log.h>
-#include <thread>
-#include <array>
#include <openssl/sha.h>
+#include <algorithm>
+#include <array>
+#include <thread>
#include "FileBlobCache.h"
#include "Properties.h"
#include "utils/TraceUtils.h"
@@ -44,8 +44,7 @@ ShaderCache& ShaderCache::get() {
}
bool ShaderCache::validateCache(const void* identity, ssize_t size) {
- if (nullptr == identity && size == 0)
- return true;
+ if (nullptr == identity && size == 0) return true;
if (nullptr == identity || size < 0) {
if (CC_UNLIKELY(Properties::debugLevel & kDebugCaches)) {
@@ -66,8 +65,7 @@ bool ShaderCache::validateCache(const void* identity, ssize_t size) {
auto key = sIDKey;
auto loaded = mBlobCache->get(&key, sizeof(key), hash.data(), hash.size());
- if (loaded && std::equal(hash.begin(), hash.end(), mIDHash.begin()))
- return true;
+ if (loaded && std::equal(hash.begin(), hash.end(), mIDHash.begin())) return true;
if (CC_UNLIKELY(Properties::debugLevel & kDebugCaches)) {
ALOGW("ShaderCache::validateCache cache validation fails");
@@ -119,7 +117,7 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) {
int maxTries = 3;
while (valueSize > mObservedBlobValueSize && maxTries > 0) {
mObservedBlobValueSize = std::min(valueSize, maxValueSize);
- void *newValueBuffer = realloc(valueBuffer, mObservedBlobValueSize);
+ void* newValueBuffer = realloc(valueBuffer, mObservedBlobValueSize);
if (!newValueBuffer) {
free(valueBuffer);
return nullptr;
@@ -133,7 +131,7 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) {
return nullptr;
}
if (valueSize > mObservedBlobValueSize) {
- ALOGE("ShaderCache::load value size is too big %d", (int) valueSize);
+ ALOGE("ShaderCache::load value size is too big %d", (int)valueSize);
free(valueBuffer);
return nullptr;
}
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index 82804cf93785..d41aadb269dd 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -16,12 +16,12 @@
#pragma once
+#include <GrContextOptions.h>
#include <cutils/compiler.h>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
-#include <GrContextOptions.h>
namespace android {
@@ -52,7 +52,7 @@ public:
* the initialized state the load and store methods will return without
* performing any cache operations.
*/
- virtual void initShaderDiskCache(const void *identity, ssize_t size);
+ virtual void initShaderDiskCache(const void* identity, ssize_t size);
virtual void initShaderDiskCache() { initShaderDiskCache(nullptr, 0); }
@@ -153,7 +153,7 @@ private:
/**
* "mObservedBlobValueSize" is the maximum value size observed by the cache reading function.
*/
- size_t mObservedBlobValueSize = 20*1024;
+ size_t mObservedBlobValueSize = 20 * 1024;
/**
* The time in seconds to wait before saving newly inserted cache entries.
@@ -176,7 +176,7 @@ private:
*/
static constexpr uint8_t sIDKey = 0;
- friend class ShaderCacheTestUtils; //used for unit testing
+ friend class ShaderCacheTestUtils; // used for unit testing
};
} /* namespace skiapipeline */
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index ac6f6a3f776d..230065c222a9 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -27,9 +27,9 @@ namespace android {
namespace uirenderer {
namespace skiapipeline {
-void SkiaDisplayList::syncContents() {
+void SkiaDisplayList::syncContents(const WebViewSyncData& data) {
for (auto& functor : mChildFunctors) {
- functor->syncFunctor();
+ functor->syncFunctor(data);
}
for (auto& animatedImage : mAnimatedImages) {
animatedImage->syncProperties();
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index d7879e722a29..3219ad1deeff 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -16,11 +16,11 @@
#pragma once
-#include "hwui/AnimatedImageDrawable.h"
#include "FunctorDrawable.h"
#include "RecordingCanvas.h"
#include "RenderNodeDrawable.h"
#include "TreeInfo.h"
+#include "hwui/AnimatedImageDrawable.h"
#include "utils/LinearAllocator.h"
#include <deque>
@@ -49,7 +49,7 @@ namespace skiapipeline {
*/
class SkiaDisplayList {
public:
- size_t getUsedSize() { return allocator.usedSize(); }
+ size_t getUsedSize() { return allocator.usedSize() + mDisplayList.usedSize(); }
~SkiaDisplayList() {
/* Given that we are using a LinearStdAllocator to store some of the
@@ -109,7 +109,7 @@ public:
* NOTE: This function can be folded into RenderNode when we no longer need
* to subclass from DisplayList
*/
- void syncContents();
+ void syncContents(const WebViewSyncData& data);
/**
* ONLY to be called by RenderNode::prepareTree in order to prepare this
diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp
index ea578cb3ec05..e48ecf490c56 100644
--- a/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp
+++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp
@@ -21,16 +21,16 @@ namespace uirenderer {
namespace skiapipeline {
SkiaMemoryTracer::SkiaMemoryTracer(std::vector<ResourcePair> resourceMap, bool itemizeType)
- : mResourceMap(resourceMap)
- , mItemizeType(itemizeType)
- , mTotalSize("bytes", 0)
- , mPurgeableSize("bytes", 0) {}
+ : mResourceMap(resourceMap)
+ , mItemizeType(itemizeType)
+ , mTotalSize("bytes", 0)
+ , mPurgeableSize("bytes", 0) {}
SkiaMemoryTracer::SkiaMemoryTracer(const char* categoryKey, bool itemizeType)
- : mCategoryKey(categoryKey)
- , mItemizeType(itemizeType)
- , mTotalSize("bytes", 0)
- , mPurgeableSize("bytes", 0) {}
+ : mCategoryKey(categoryKey)
+ , mItemizeType(itemizeType)
+ , mTotalSize("bytes", 0)
+ , mPurgeableSize("bytes", 0) {}
const char* SkiaMemoryTracer::mapName(const char* resourceName) {
for (auto& resource : mResourceMap) {
@@ -42,7 +42,7 @@ const char* SkiaMemoryTracer::mapName(const char* resourceName) {
}
void SkiaMemoryTracer::processElement() {
- if(!mCurrentElement.empty()) {
+ if (!mCurrentElement.empty()) {
// Only count elements that contain "size", other values just provide metadata.
auto sizeResult = mCurrentValues.find("size");
if (sizeResult != mCurrentValues.end()) {
@@ -136,8 +136,8 @@ void SkiaMemoryTracer::logOutput(String8& log) {
for (const auto& typedValue : namedItem.second) {
TraceValue traceValue = convertUnits(typedValue.second);
const char* entry = (traceValue.count > 1) ? "entries" : "entry";
- log.appendFormat(" %s: %.2f %s (%d %s)\n", typedValue.first,
- traceValue.value, traceValue.units, traceValue.count, entry);
+ log.appendFormat(" %s: %.2f %s (%d %s)\n", typedValue.first, traceValue.value,
+ traceValue.units, traceValue.count, entry);
}
} else {
auto result = namedItem.second.find("size");
diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.h b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h
index abf1f4b052ce..e9a7981ef028 100644
--- a/libs/hwui/pipeline/skia/SkiaMemoryTracer.h
+++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h
@@ -50,8 +50,8 @@ public:
}
bool shouldDumpWrappedObjects() const override { return true; }
- void setMemoryBacking(const char*, const char*, const char*) override { }
- void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override { }
+ void setMemoryBacking(const char*, const char*, const char*) override {}
+ void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {}
private:
struct TraceValue {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 142bca95e598..4338b1cc2a21 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -155,29 +155,24 @@ void SkiaOpenGLPipeline::onStop() {
}
}
-bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
+bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
ColorMode colorMode) {
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
}
+ setSurfaceColorProperties(colorMode);
+
if (surface) {
mRenderThread.requireGlContext();
- auto newSurface = mEglManager.createSurface(surface, colorMode);
+ auto newSurface = mEglManager.createSurface(surface, colorMode, mSurfaceColorGamut);
if (!newSurface) {
return false;
}
mEglSurface = newSurface.unwrap();
}
- if (colorMode == ColorMode::SRGB) {
- mSurfaceColorType = SkColorType::kN32_SkColorType;
- } else if (colorMode == ColorMode::WideColorGamut) {
- mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType;
- }
- mSurfaceColorSpace = SkColorSpace::MakeSRGB();
-
if (mEglSurface != EGL_NO_SURFACE) {
const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 4ab3541d447b..479910697871 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -42,7 +42,7 @@ public:
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
- bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
+ bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 7a255c15bf5f..2e7850d48e54 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -17,6 +17,7 @@
#include "SkiaPipeline.h"
#include <SkImageEncoder.h>
+#include <SkImageInfo.h>
#include <SkImagePriv.h>
#include <SkOverdrawCanvas.h>
#include <SkOverdrawColorFilter.h>
@@ -183,15 +184,15 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator
} else {
String8 cachesOutput;
mRenderThread.cacheManager().dumpMemoryUsage(cachesOutput,
- &mRenderThread.renderState());
+ &mRenderThread.renderState());
ALOGE("%s", cachesOutput.string());
if (errorHandler) {
std::ostringstream err;
err << "Unable to create layer for " << node->getName();
const int maxTextureSize = DeviceInfo::get()->maxTextureSize();
err << ", size " << info.width() << "x" << info.height() << " max size "
- << maxTextureSize << " color type " << (int)info.colorType()
- << " has context " << (int)(mRenderThread.getGrContext() != nullptr);
+ << maxTextureSize << " color type " << (int)info.colorType() << " has context "
+ << (int)(mRenderThread.getGrContext() != nullptr);
errorHandler->onError(err.str());
}
}
@@ -300,8 +301,7 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
mSavePictureProcessor->savePicture(data, mCapturedFile);
} else {
mSavePictureProcessor->savePicture(
- data,
- mCapturedFile + "_" + std::to_string(mCaptureSequence));
+ data, mCapturedFile + "_" + std::to_string(mCaptureSequence));
}
mCaptureSequence--;
}
@@ -453,6 +453,20 @@ void SkiaPipeline::dumpResourceCacheUsage() const {
ALOGD("%s", log.c_str());
}
+void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
+ if (colorMode == ColorMode::SRGB) {
+ mSurfaceColorType = SkColorType::kN32_SkColorType;
+ mSurfaceColorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
+ mSurfaceColorSpace = SkColorSpace::MakeSRGB();
+ } else if (colorMode == ColorMode::WideColorGamut) {
+ mSurfaceColorType = DeviceInfo::get()->getWideColorType();
+ mSurfaceColorGamut = DeviceInfo::get()->getWideColorGamut();
+ mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
+ } else {
+ LOG_ALWAYS_FATAL("Unreachable: unsupported color mode.");
+ }
+}
+
// Overdraw debugging
// These colors should be kept in sync with Caches::getOverdrawColor() with a few differences.
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 42a411a6808c..ff873133c6fb 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -30,7 +30,7 @@ namespace skiapipeline {
class SkiaPipeline : public renderthread::IRenderPipeline {
public:
- SkiaPipeline(renderthread::RenderThread& thread);
+ explicit SkiaPipeline(renderthread::RenderThread& thread);
virtual ~SkiaPipeline();
TaskManager* getTaskManager() override;
@@ -97,8 +97,7 @@ public:
return mLightCenter;
}
- static void updateLighting(const LightGeometry& lightGeometry,
- const LightInfo& lightInfo) {
+ static void updateLighting(const LightGeometry& lightGeometry, const LightInfo& lightInfo) {
mLightRadius = lightGeometry.radius;
mAmbientShadowAlpha = lightInfo.ambientShadowAlpha;
mSpotShadowAlpha = lightInfo.spotShadowAlpha;
@@ -107,9 +106,11 @@ public:
protected:
void dumpResourceCacheUsage() const;
+ void setSurfaceColorProperties(renderthread::ColorMode colorMode);
renderthread::RenderThread& mRenderThread;
SkColorType mSurfaceColorType;
+ SkColorSpace::Gamut mSurfaceColorGamut;
sk_sp<SkColorSpace> mSurfaceColorSpace;
private:
diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
index daa4c1839693..dc8420f4e01b 100644
--- a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
+++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
@@ -23,7 +23,7 @@ namespace uirenderer {
class SkiaProfileRenderer : public IProfileRenderer {
public:
- SkiaProfileRenderer(SkCanvas* canvas) : mCanvas(canvas) {}
+ explicit SkiaProfileRenderer(SkCanvas* canvas) : mCanvas(canvas) {}
void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
void drawRects(const float* rects, int count, const SkPaint& paint) override;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index b682ab0256dd..6eefed959913 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -24,6 +24,7 @@
#include "RenderNode.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/GLFunctorDrawable.h"
+#include "pipeline/skia/VkFunctorDrawable.h"
#include "pipeline/skia/VkInteropFunctorDrawable.h"
namespace android {
@@ -94,8 +95,8 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
drawDrawable(drawable);
}
if (enableReorder) {
- mCurrentBarrier = mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
- mDisplayList.get());
+ mCurrentBarrier =
+ mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(mDisplayList.get());
drawDrawable(mCurrentBarrier);
}
}
@@ -124,11 +125,27 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
uirenderer::GlFunctorLifecycleListener* listener) {
FunctorDrawable* functorDrawable;
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor,
- listener, asSkCanvas());
+ // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the
+ // interop is disabled/moved.
+ functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(
+ functor, listener, asSkCanvas());
} else {
- functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener,
- asSkCanvas());
+ functorDrawable =
+ mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener, asSkCanvas());
+ }
+ mDisplayList->mChildFunctors.push_back(functorDrawable);
+ drawDrawable(functorDrawable);
+}
+
+void SkiaRecordingCanvas::drawWebViewFunctor(int functor) {
+ FunctorDrawable* functorDrawable;
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the
+ // interop is disabled.
+ functorDrawable =
+ mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor, asSkCanvas());
+ } else {
+ functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas());
}
mDisplayList->mChildFunctors.push_back(functorDrawable);
drawDrawable(functorDrawable);
@@ -164,7 +181,7 @@ SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint,
if (colorSpaceFilter) {
if (tmpPaint.getColorFilter()) {
tmpPaint.setColorFilter(SkColorFilter::MakeComposeFilter(
- tmpPaint.refColorFilter(), std::move(colorSpaceFilter)));
+ tmpPaint.refColorFilter(), std::move(colorSpaceFilter)));
} else {
tmpPaint.setColorFilter(std::move(colorSpaceFilter));
}
@@ -245,8 +262,7 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch
filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality);
}
sk_sp<SkImage> image = bitmap.makeImage();
- mRecorder.drawImageLattice(image, lattice, dst,
- filterPaint(std::move(filteredPaint)),
+ mRecorder.drawImageLattice(image, lattice, dst, filterPaint(std::move(filteredPaint)),
bitmap.palette());
if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index d6107a9d9969..afeccea3fb70 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -74,6 +74,7 @@ public:
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
virtual void callDrawGLFunction(Functor* functor,
uirenderer::GlFunctorLifecycleListener* listener) override;
+ void drawWebViewFunctor(int functor) override;
private:
RecordingCanvas mRecorder;
diff --git a/libs/hwui/pipeline/skia/SkiaUtils.h b/libs/hwui/pipeline/skia/SkiaUtils.h
index 834446905216..fa7f1fe2f746 100644
--- a/libs/hwui/pipeline/skia/SkiaUtils.h
+++ b/libs/hwui/pipeline/skia/SkiaUtils.h
@@ -22,7 +22,7 @@ namespace android {
static inline SkRect SkRectMakeLargest() {
const SkScalar v = SK_ScalarMax;
- return { -v, -v, v, v };
+ return {-v, -v, v, v};
};
} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index a494e490aea1..1d3a24463057 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -20,9 +20,9 @@
#include "Readback.h"
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
+#include "VkInteropFunctorDrawable.h"
#include "renderstate/RenderState.h"
#include "renderthread/Frame.h"
-#include "VkInteropFunctorDrawable.h"
#include <SkSurface.h>
#include <SkTypes.h>
@@ -115,21 +115,17 @@ DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
void SkiaVulkanPipeline::onStop() {}
-bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
+bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
ColorMode colorMode) {
if (mVkSurface) {
mVkManager.destroySurface(mVkSurface);
mVkSurface = nullptr;
}
+ setSurfaceColorProperties(colorMode);
if (surface) {
- mVkSurface = mVkManager.createSurface(surface, colorMode);
- }
-
- if (colorMode == ColorMode::SRGB) {
- mSurfaceColorType = SkColorType::kN32_SkColorType;
- } else if (colorMode == ColorMode::WideColorGamut) {
- mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType;
+ mVkSurface = mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace,
+ mSurfaceColorGamut, mSurfaceColorType);
}
return mVkSurface != nullptr;
@@ -162,7 +158,7 @@ sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThr
ALOGW("SkiaVulkanPipeline::allocateHardwareBitmap() failed in GraphicBuffer.create()");
return nullptr;
}
- return sk_sp<Bitmap>(new Bitmap(buffer.get(), skBitmap.info()));
+ return Bitmap::createFrom(buffer, skBitmap.refColorSpace());
}
} /* namespace skiapipeline */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 14c0d69dba33..53ffc4422fd7 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -25,7 +25,7 @@ namespace skiapipeline {
class SkiaVulkanPipeline : public SkiaPipeline {
public:
- SkiaVulkanPipeline(renderthread::RenderThread& thread);
+ explicit SkiaVulkanPipeline(renderthread::RenderThread& thread);
virtual ~SkiaVulkanPipeline() {}
renderthread::MakeCurrentResult makeCurrent() override;
@@ -38,7 +38,7 @@ public:
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
- bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
+ bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
index 74e48cea2a87..5e892aa7e92c 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
@@ -62,8 +62,8 @@ class VectorDrawableAtlas : public virtual RefBase {
public:
enum class StorageMode { allowSharedSurface, disallowSharedSurface };
- VectorDrawableAtlas(size_t surfaceArea,
- StorageMode storageMode = StorageMode::allowSharedSurface);
+ explicit VectorDrawableAtlas(size_t surfaceArea,
+ StorageMode storageMode = StorageMode::allowSharedSurface);
/**
* "prepareForDraw" may allocate a new surface if needed. It may schedule to repack the
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
new file mode 100644
index 000000000000..156f74a611a7
--- /dev/null
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#include "VkFunctorDrawable.h"
+#include <private/hwui/DrawVkInfo.h>
+
+#include <GrBackendDrawableInfo.h>
+#include <SkImage.h>
+#include <utils/Color.h>
+#include <utils/Trace.h>
+#include <utils/TraceUtils.h>
+#include <vk/GrVkTypes.h>
+#include <thread>
+#include "thread/ThreadBase.h"
+#include "utils/TimeUtils.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+VkFunctorDrawHandler::VkFunctorDrawHandler(Functor* functor) : INHERITED(), mFunctor(functor) {}
+
+VkFunctorDrawHandler::~VkFunctorDrawHandler() {
+ // TODO(cblume) Fill in the DrawVkInfo parameters.
+ (*mFunctor)(DrawVkInfo::kModePostComposite, nullptr);
+}
+
+void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
+ ATRACE_CALL();
+
+ GrVkDrawableInfo vulkan_info;
+ if (!info.getVkDrawableInfo(&vulkan_info)) {
+ return;
+ }
+
+ DrawVkInfo draw_vk_info;
+ // TODO(cblume) Fill in the rest of the parameters and test the actual call.
+ draw_vk_info.isLayer = true;
+
+ (*mFunctor)(DrawVkInfo::kModeComposite, &draw_vk_info);
+}
+
+VkFunctorDrawable::~VkFunctorDrawable() {
+ if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
+ if (lp->listener) {
+ lp->listener->onGlFunctorReleased(lp->functor);
+ }
+ }
+}
+
+void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) {
+ LOG_ALWAYS_FATAL("VkFunctorDrawable::onDraw() should never be called.");
+ // Instead of calling onDraw(), the call should come from onSnapGpuDrawHandler.
+}
+
+std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDrawHandler(
+ GrBackendApi backendApi, const SkMatrix& matrix) {
+ if (backendApi != GrBackendApi::kVulkan) {
+ return nullptr;
+ }
+ std::unique_ptr<VkFunctorDrawHandler> draw;
+ if (mAnyFunctor.index() == 0) {
+ LOG_ALWAYS_FATAL("Not implemented");
+ return nullptr;
+ } else {
+ return std::make_unique<VkFunctorDrawHandler>(std::get<1>(mAnyFunctor).functor);
+ }
+}
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
new file mode 100644
index 000000000000..d6fefc1fca06
--- /dev/null
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "FunctorDrawable.h"
+
+#include <SkImageInfo.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+/**
+ * This draw handler will be returned by VkFunctorDrawable's onSnapGpuDrawHandler. It allows us to
+ * issue Vulkan commands while the command buffer is being flushed.
+ */
+class VkFunctorDrawHandler : public FunctorDrawable::GpuDrawHandler {
+public:
+ explicit VkFunctorDrawHandler(Functor* functor);
+ ~VkFunctorDrawHandler() override;
+
+ void draw(const GrBackendDrawableInfo& info) override;
+
+private:
+ typedef GpuDrawHandler INHERITED;
+
+ Functor* mFunctor;
+};
+
+/**
+ * This drawable wraps a Vulkan functor enabling it to be recorded into a list of Skia drawing
+ * commands.
+ */
+class VkFunctorDrawable : public FunctorDrawable {
+public:
+ using FunctorDrawable::FunctorDrawable;
+
+ ~VkFunctorDrawable() override;
+
+protected:
+ // SkDrawable functions:
+ void onDraw(SkCanvas* canvas) override;
+ std::unique_ptr<FunctorDrawable::GpuDrawHandler> onSnapGpuDrawHandler(
+ GrBackendApi backendApi, const SkMatrix& matrix) override;
+};
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index 004a558dd9d0..c3563dbfd3cd 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -17,13 +17,13 @@
#include "VkInteropFunctorDrawable.h"
#include <private/hwui/DrawGlInfo.h>
-#include "renderthread/EglManager.h"
-#include "thread/ThreadBase.h"
-#include "utils/TimeUtils.h"
-#include <thread>
#include <utils/Color.h>
#include <utils/Trace.h>
#include <utils/TraceUtils.h>
+#include <thread>
+#include "renderthread/EglManager.h"
+#include "thread/ThreadBase.h"
+#include "utils/TimeUtils.h"
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
@@ -36,44 +36,29 @@ namespace android {
namespace uirenderer {
namespace skiapipeline {
-static std::mutex sLock{};
-static ThreadBase* sGLDrawThread = nullptr;
static renderthread::EglManager sEglManager;
// ScopedDrawRequest makes sure a GL thread is started and EGL context is initialized on it.
class ScopedDrawRequest {
public:
ScopedDrawRequest() { beginDraw(); }
+
private:
void beginDraw() {
- std::lock_guard{sLock};
-
- if (!sGLDrawThread) {
- sGLDrawThread = new ThreadBase{};
- }
-
- if (!sGLDrawThread->isRunning()) {
- sGLDrawThread->start("GLFunctorThread");
- }
-
if (!sEglManager.hasEglContext()) {
- sGLDrawThread->queue().runSync([]() {
- sEglManager.initialize();
- });
+ sEglManager.initialize();
}
}
};
void VkInteropFunctorDrawable::vkInvokeFunctor(Functor* functor) {
ScopedDrawRequest _drawRequest{};
- sGLDrawThread->queue().runSync([&]() {
- EGLDisplay display = sEglManager.eglDisplay();
- DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
- if (display != EGL_NO_DISPLAY) {
- mode = DrawGlInfo::kModeProcess;
- }
- (*functor)(mode, nullptr);
- });
+ EGLDisplay display = sEglManager.eglDisplay();
+ DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
+ if (display != EGL_NO_DISPLAY) {
+ mode = DrawGlInfo::kModeProcess;
+ }
+ (*functor)(mode, nullptr);
}
#define FENCE_TIMEOUT 2000000000
@@ -93,14 +78,14 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
if (!mFrameBuffer.get() || mFBInfo != surfaceInfo) {
// Buffer will be used as an OpenGL ES render target.
mFrameBuffer = new GraphicBuffer(
- //TODO: try to reduce the size of the buffer: possibly by using clip bounds.
- static_cast<uint32_t>(surfaceInfo.width()),
- static_cast<uint32_t>(surfaceInfo.height()),
- ColorTypeToPixelFormat(surfaceInfo.colorType()),
- GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER,
- std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) +
- "]");
+ // TODO: try to reduce the size of the buffer: possibly by using clip bounds.
+ static_cast<uint32_t>(surfaceInfo.width()),
+ static_cast<uint32_t>(surfaceInfo.height()),
+ ColorTypeToPixelFormat(surfaceInfo.colorType()),
+ GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
+ GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER,
+ std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) +
+ "]");
status_t error = mFrameBuffer->initCheck();
if (error < 0) {
ALOGW("VkInteropFunctorDrawable::onDraw() failed in GraphicBuffer.create()");
@@ -110,16 +95,15 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
mFBInfo = surfaceInfo;
}
- //TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan
- //TODO: draw command has completed.
- //TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See
- //TODO: GrVkGpu::destroyResources() for example.
- bool success = sGLDrawThread->queue().runSync([&]() -> bool {
+ // TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan
+ // TODO: draw command has completed.
+ // TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See
+ // TODO: GrVkGpu::destroyResources() for example.
+ {
ATRACE_FORMAT("WebViewDraw_%dx%d", mFBInfo.width(), mFBInfo.height());
EGLDisplay display = sEglManager.eglDisplay();
- LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
- "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
// We use an EGLImage to access the content of the GraphicBuffer
// The EGL image is later bound to a 2D texture
EGLClientBuffer clientBuffer = (EGLClientBuffer)mFrameBuffer->getNativeBuffer();
@@ -127,7 +111,7 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
if (autoImage.image == EGL_NO_IMAGE_KHR) {
ALOGW("Could not create EGL image, err =%s",
uirenderer::renderthread::EglManager::eglErrorString());
- return false;
+ return;
}
AutoSkiaGlTexture glTexture;
@@ -154,11 +138,11 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
AutoGLFramebuffer glFb;
// Bind texture to the frame buffer.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- glTexture.mTexture, 0);
+ glTexture.mTexture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
ALOGE("Failed framebuffer check for created target buffer: %s",
- GLUtils::getGLFramebufferError());
- return false;
+ GLUtils::getGLFramebufferError());
+ return;
}
glDisable(GL_STENCIL_TEST);
@@ -166,27 +150,25 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
- (*mFunctor)(DrawGlInfo::kModeDraw, &info);
+ if (mAnyFunctor.index() == 0) {
+ std::get<0>(mAnyFunctor).handle->drawGl(info);
+ } else {
+ (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info);
+ }
EGLSyncKHR glDrawFinishedFence =
eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
LOG_ALWAYS_FATAL_IF(glDrawFinishedFence == EGL_NO_SYNC_KHR,
- "Could not create sync fence %#x", eglGetError());
+ "Could not create sync fence %#x", eglGetError());
glFlush();
// TODO: export EGLSyncKHR in file descr
// TODO: import file desc in Vulkan Semaphore
// TODO: instead block the GPU: probably by using external Vulkan semaphore.
// Block the CPU until the glFlush finish.
- EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0,
- FENCE_TIMEOUT);
+ EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0, FENCE_TIMEOUT);
LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
"Failed to wait for the fence %#x", eglGetError());
eglDestroySyncKHR(display, glDrawFinishedFence);
- return true;
- });
-
- if (!success) {
- return;
}
SkPaint paint;
@@ -197,26 +179,24 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) {
canvas->resetMatrix();
auto functorImage = SkImage::MakeFromAHardwareBuffer(
- reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType,
- nullptr, kBottomLeft_GrSurfaceOrigin);
+ reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType, nullptr,
+ kBottomLeft_GrSurfaceOrigin);
canvas->drawImage(functorImage, 0, 0, &paint);
canvas->restore();
}
VkInteropFunctorDrawable::~VkInteropFunctorDrawable() {
- if (mListener.get() != nullptr) {
- ScopedDrawRequest _drawRequest{};
- sGLDrawThread->queue().runSync([&]() {
- mListener->onGlFunctorReleased(mFunctor);
- });
+ if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
+ if (lp->listener) {
+ ScopedDrawRequest _drawRequest{};
+ lp->listener->onGlFunctorReleased(lp->functor);
+ }
}
}
-void VkInteropFunctorDrawable::syncFunctor() const {
+void VkInteropFunctorDrawable::syncFunctor(const WebViewSyncData& data) const {
ScopedDrawRequest _drawRequest{};
- sGLDrawThread->queue().runSync([&]() {
- (*mFunctor)(DrawGlInfo::kModeSync, nullptr);
- });
+ FunctorDrawable::syncFunctor(data);
}
} // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
index 8fe52c5ef700..c47ee114263f 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h
@@ -18,8 +18,8 @@
#include "FunctorDrawable.h"
-#include <utils/RefBase.h>
#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
namespace android {
namespace uirenderer {
@@ -32,20 +32,18 @@ namespace skiapipeline {
*/
class VkInteropFunctorDrawable : public FunctorDrawable {
public:
- VkInteropFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener,
- SkCanvas* canvas)
- : FunctorDrawable(functor, listener, canvas) {}
- virtual ~VkInteropFunctorDrawable();
+ using FunctorDrawable::FunctorDrawable;
- void syncFunctor() const override;
+ virtual ~VkInteropFunctorDrawable();
static void vkInvokeFunctor(Functor* functor);
+ void syncFunctor(const WebViewSyncData& data) const override;
+
protected:
virtual void onDraw(SkCanvas* canvas) override;
private:
-
// Variables below describe/store temporary offscreen buffer used for Vulkan pipeline.
sp<GraphicBuffer> mFrameBuffer;
SkImageInfo mFBInfo;
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
new file mode 100644
index 000000000000..b2351fc026de
--- /dev/null
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HWUI_DRAW_VK_INFO_H
+#define ANDROID_HWUI_DRAW_VK_INFO_H
+
+#include <vulkan/vulkan.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Structure used by VulkanRenderer::callDrawVKFunction() to pass and receive data from Vulkan
+ * functors.
+ */
+struct DrawVkInfo {
+ // Input: current width/height of destination surface
+ int width;
+ int height;
+
+ // Input: is the render target an FBO
+ bool isLayer;
+
+ // Input: current transform matrix, in OpenGL format
+ float transform[16];
+
+ // Input: WebView should do its main compositing draws into this. It cannot do anything that
+ // would require stopping the render pass.
+ VkCommandBuffer secondaryCommandBuffer;
+
+ // Input: The main color attachment index where secondaryCommandBuffer will eventually be
+ // submitted.
+ uint32_t colorAttachmentIndex;
+
+ // Input: A render pass which will be compatible to the one which the secondaryCommandBuffer
+ // will be submitted into.
+ VkRenderPass compatibleRenderPass;
+
+ // Input: Format of the destination surface.
+ VkFormat format;
+
+ // Input: Color space transfer params
+ float g;
+ float a;
+ float b;
+ float c;
+ float d;
+ float e;
+ float f;
+
+ // Input: Color space transformation from linear RGB to D50-adapted XYZ
+ float colorSpaceTransform[9];
+
+ // Input: current clip rect
+ int clipLeft;
+ int clipTop;
+ int clipRight;
+ int clipBottom;
+
+ /**
+ * Values used as the "what" parameter of the functor.
+ */
+ enum Mode {
+ // Called once at WebView start
+ kModeInit,
+ // Called when things need to be re-created
+ kModeReInit,
+ // Notifies the app that the composite functor will be called soon. This allows WebView to
+ // begin work early.
+ kModePreComposite,
+ // Do the actual composite work
+ kModeComposite,
+ // This allows WebView to begin using the previously submitted objects in future work.
+ kModePostComposite,
+ // Invoked every time the UI thread pushes over a frame to the render thread and the owning
+ // view has a dirty display list*. This is a signal to sync any data that needs to be
+ // shared between the UI thread and the render thread. During this time the UI thread is
+ // blocked.
+ kModeSync
+ };
+
+ /**
+ * Values used by Vulkan functors to tell the framework what to do next.
+ */
+ enum Status {
+ // The functor is done
+ kStatusDone = 0x0,
+ };
+}; // struct DrawVkInfo
+
+} // namespace uirenderer
+} // namespace android
+
+#endif // ANDROID_HWUI_DRAW_VK_INFO_H
diff --git a/libs/hwui/private/hwui/WebViewFunctor.h b/libs/hwui/private/hwui/WebViewFunctor.h
new file mode 100644
index 000000000000..da3d06a4d60c
--- /dev/null
+++ b/libs/hwui/private/hwui/WebViewFunctor.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
+#define FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
+
+#include <cutils/compiler.h>
+#include <private/hwui/DrawGlInfo.h>
+
+namespace android::uirenderer {
+
+enum class RenderMode {
+ OpenGL_ES,
+ Vulkan,
+};
+
+// Static for the lifetime of the process
+ANDROID_API RenderMode WebViewFunctor_queryPlatformRenderMode();
+
+struct WebViewSyncData {
+ bool applyForceDark;
+};
+
+struct WebViewFunctorCallbacks {
+ // kModeSync, called on RenderThread
+ void (*onSync)(int functor, void* data, const WebViewSyncData& syncData);
+
+ // Called when either the context is destroyed _or_ when the functor's last reference goes
+ // away. Will always be called with an active context and always on renderthread.
+ void (*onContextDestroyed)(int functor, void* data);
+
+ // Called when the last reference to the handle goes away and the handle is considered
+ // irrevocably destroyed. Will always be proceeded by a call to onContextDestroyed if
+ // this functor had ever been drawn.
+ void (*onDestroyed)(int functor, void* data);
+
+ union {
+ struct {
+ // Called on RenderThread. initialize is guaranteed to happen before this call
+ void (*draw)(int functor, void* data, const DrawGlInfo& params);
+ } gles;
+ // TODO: VK support. The current DrawVkInfo is monolithic and needs to be split up for
+ // what params are valid on what callbacks
+ struct {
+ // Called either the first time the functor is used or the first time it's used after
+ // a call to onContextDestroyed.
+ // void (*initialize)(int functor, const InitParams& params);
+ // void (*frameStart)(int functor, /* todo: what params are actually needed for this to
+ // be useful? Is this useful? */)
+ // void (*draw)(int functor, const CompositeParams& params /* todo: rename - composite
+ // almost always means something else, and we aren't compositing */);
+ // void (*frameEnd)(int functor, const PostCompositeParams& params /* todo: same as
+ // CompositeParams - rename */);
+ } vk;
+ };
+};
+
+// Creates a new WebViewFunctor from the given prototype. The prototype is copied after
+// this function returns. Caller retains full ownership of it.
+// Returns -1 if the creation fails (such as an unsupported functorMode + platform mode combination)
+ANDROID_API int WebViewFunctor_create(void* data, const WebViewFunctorCallbacks& prototype, RenderMode functorMode);
+
+// May be called on any thread to signal that the functor should be destroyed.
+// The functor will receive an onDestroyed when the last usage of it is released,
+// and it should be considered alive & active until that point.
+ANDROID_API void WebViewFunctor_release(int functor);
+
+} // namespace android::uirenderer
+
+#endif // FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 7acc44ca65b7..6c04232ab7f5 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -30,6 +30,7 @@
#include <gui/Surface.h>
#include <math.h>
#include <set>
+#include <SkMathPriv.h>
namespace android {
namespace uirenderer {
@@ -42,11 +43,6 @@ namespace renderthread {
#define SURFACE_SIZE_MULTIPLIER (12.0f * 4.0f)
#define BACKGROUND_RETENTION_PERCENTAGE (0.5f)
-// for super large fonts we will draw them as paths so no need to keep linearly
-// increasing the font cache size.
-#define FONT_CACHE_MIN_MB (0.5f)
-#define FONT_CACHE_MAX_MB (4.0f)
-
CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display.w * display.h) {
mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
mMaxSurfaceArea / 2,
@@ -106,25 +102,10 @@ public:
void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) {
contextOptions->fAllowPathMaskCaching = true;
- float screenMP = mMaxSurfaceArea / 1024.0f / 1024.0f;
- float fontCacheMB = 0;
- float decimalVal = std::modf(screenMP, &fontCacheMB);
-
- // This is a basic heuristic to size the cache to a multiple of 512 KB
- if (decimalVal > 0.8f) {
- fontCacheMB += 1.0f;
- } else if (decimalVal > 0.5f) {
- fontCacheMB += 0.5f;
- }
-
- // set limits on min/max size of the cache
- fontCacheMB = std::max(FONT_CACHE_MIN_MB, std::min(FONT_CACHE_MAX_MB, fontCacheMB));
-
- // We must currently set the size of the text cache based on the size of the
- // display even though we like to be dynamicallysizing it to the size of the window.
- // Skia's implementation doesn't provide a mechanism to resize the font cache due to
- // the potential cost of recreating the glyphs.
- contextOptions->fGlyphCacheTextureMaximumBytes = fontCacheMB * 1024 * 1024;
+ // This sets the maximum size for a single texture atlas in the GPU font cache. If necessary,
+ // the cache can allocate additional textures that are counted against the total cache limits
+ // provided to Skia.
+ contextOptions->fGlyphCacheTextureMaximumBytes = GrNextSizePow2(mMaxSurfaceArea);
if (mTaskManager.canRunTasks()) {
if (!mTaskProcessor.get()) {
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index 35fc91a42510..66f04f1ba266 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -59,7 +59,7 @@ public:
private:
friend class RenderThread;
- CacheManager(const DisplayInfo& display);
+ explicit CacheManager(const DisplayInfo& display);
void reset(sk_sp<GrContext> grContext);
void destroy();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index f1a522ecd588..8e57a3a119e3 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -142,7 +142,12 @@ void CanvasContext::destroy() {
void CanvasContext::setSurface(sp<Surface>&& surface) {
ATRACE_CALL();
- mNativeSurface = std::move(surface);
+ if (surface) {
+ mNativeSurface = new ReliableSurface{std::move(surface)};
+ mNativeSurface->setDequeueTimeout(500_ms);
+ } else {
+ mNativeSurface = nullptr;
+ }
ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode);
@@ -285,10 +290,11 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
info.damageAccumulator = &mDamageAccumulator;
info.layerUpdateQueue = &mLayerUpdateQueue;
+ info.out.canDrawThisFrame = true;
mAnimationContext->startFrame(info.mode);
mRenderPipeline->onPrepareTree();
- for (const sp<RenderNode>& node : mRenderNodes) {
+ for (const sp<RenderNode> &node : mRenderNodes) {
// Only the primary target node will be drawn full - all other nodes would get drawn in
// real time mode. In case of a window, the primary node is the window content and the other
// node(s) are non client / filler nodes.
@@ -304,7 +310,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
mIsDirty = true;
- if (CC_UNLIKELY(!mNativeSurface.get())) {
+ if (CC_UNLIKELY(!hasSurface())) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
info.out.canDrawThisFrame = false;
return;
@@ -312,7 +318,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) {
nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
- SwapHistory& lastSwap = mSwapHistory.back();
+ SwapHistory &lastSwap = mSwapHistory.back();
nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
// The slight fudge-factor is to deal with cases where
// the vsync was estimated due to being slow handling the signal.
@@ -323,25 +329,6 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
// the deadline for RT animations
info.out.canDrawThisFrame = false;
}
- /* This logic exists to try and recover from a display latch miss, which essentially
- * results in the bufferqueue being double-buffered instead of triple-buffered.
- * SurfaceFlinger itself now tries to handle & recover from this situation, so this
- * logic should no longer be necessary. As it's occasionally triggering when
- * undesired disable it.
- * TODO: Remove this entirely if the results are solid.
- else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 ||
- (latestVsync - mLastDropVsync) < 500_ms) {
- // It's been several frame intervals, assume the buffer queue is fine
- // or the last drop was too recent
- info.out.canDrawThisFrame = true;
- } else {
- info.out.canDrawThisFrame = !isSwapChainStuffed();
- if (!info.out.canDrawThisFrame) {
- // dropping frame
- mLastDropVsync = mRenderThread.timeLord().latestVsync();
- }
- }
- */
} else {
info.out.canDrawThisFrame = true;
}
@@ -352,7 +339,19 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t sy
info.out.canDrawThisFrame = false;
}
- if (!info.out.canDrawThisFrame) {
+ if (info.out.canDrawThisFrame) {
+ int err = mNativeSurface->reserveNext();
+ if (err != OK) {
+ mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
+ info.out.canDrawThisFrame = false;
+ ALOGW("reserveNext failed, error = %d (%s)", err, strerror(-err));
+ if (err != TIMED_OUT) {
+ // A timed out surface can still recover, but assume others are permanently dead.
+ setSurface(nullptr);
+ return;
+ }
+ }
+ } else {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
}
@@ -577,8 +576,7 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) {
ATRACE_CALL();
if (level >= TRIM_MEMORY_COMPLETE) {
thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
- thread.destroyGlContext();
- thread.vulkanManager().destroy();
+ thread.destroyRenderingContext();
} else if (level >= TRIM_MEMORY_UI_HIDDEN) {
thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden);
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 70be4a6d7730..9e7abf447cd6 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -25,6 +25,7 @@
#include "IRenderPipeline.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
+#include "ReliableSurface.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
#include "thread/Task.h"
@@ -219,7 +220,7 @@ private:
EGLint mLastFrameHeight = 0;
RenderThread& mRenderThread;
- sp<Surface> mNativeSurface;
+ sp<ReliableSurface> mNativeSurface;
// stopped indicates the CanvasContext will reject actual redraw operations,
// and defer repaint until it is un-stopped
bool mStopped = false;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 65ced6ad9316..8cd97ed20215 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -31,6 +31,8 @@
#include <string>
#include <vector>
+#include <system/window.h>
+#include <gui/Surface.h>
#define GLES_VERSION 2
@@ -87,10 +89,13 @@ EglManager::EglManager()
, mEglConfigWideGamut(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
- , mCurrentSurface(EGL_NO_SURFACE) {}
+ , mCurrentSurface(EGL_NO_SURFACE)
+ , mHasWideColorGamutSupport(false) {}
EglManager::~EglManager() {
- destroy();
+ if (hasEglContext()) {
+ ALOGW("~EglManager() leaked an EGL context");
+ }
}
void EglManager::initialize() {
@@ -106,7 +111,7 @@ void EglManager::initialize() {
LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
"Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString());
- ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
+ ALOGV("Initialized EGL, version %d.%d", (int)major, (int)minor);
initExtensions();
@@ -126,6 +131,81 @@ void EglManager::initialize() {
createContext();
createPBufferSurface();
makeCurrent(mPBufferSurface, nullptr, /* force */ true);
+
+ SkColorSpace::Gamut wideColorGamut = DeviceInfo::get()->getWideColorGamut();
+ bool hasWideColorSpaceExtension = false;
+ if (wideColorGamut == SkColorSpace::Gamut::kDCIP3_D65_Gamut) {
+ hasWideColorSpaceExtension = EglExtensions.displayP3;
+ } else if (wideColorGamut == SkColorSpace::Gamut::kSRGB_Gamut) {
+ hasWideColorSpaceExtension = EglExtensions.scRGB;
+ } else {
+ LOG_ALWAYS_FATAL("Unsupported wide color space.");
+ }
+ mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension &&
+ mEglConfigWideGamut != EGL_NO_CONFIG_KHR;
+}
+
+EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
+ EGLint eglSwapBehavior =
+ (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+ EGLint attribs[] = {EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_CONFIG_CAVEAT,
+ EGL_NONE,
+ EGL_STENCIL_SIZE,
+ STENCIL_BUFFER_SIZE,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | eglSwapBehavior,
+ EGL_NONE};
+ EGLConfig config = EGL_NO_CONFIG_KHR;
+ EGLint numConfigs = 1;
+ if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) ||
+ numConfigs != 1) {
+ return EGL_NO_CONFIG_KHR;
+ }
+ return config;
+}
+
+EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior) {
+ EGLint eglSwapBehavior =
+ (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+ // If we reached this point, we have a valid swap behavior
+ EGLint attribs[] = {EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_COLOR_COMPONENT_TYPE_EXT,
+ EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
+ EGL_RED_SIZE,
+ 16,
+ EGL_GREEN_SIZE,
+ 16,
+ EGL_BLUE_SIZE,
+ 16,
+ EGL_ALPHA_SIZE,
+ 16,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_STENCIL_SIZE,
+ STENCIL_BUFFER_SIZE,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | eglSwapBehavior,
+ EGL_NONE};
+ EGLConfig config = EGL_NO_CONFIG_KHR;
+ EGLint numConfigs = 1;
+ if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) ||
+ numConfigs != 1) {
+ return EGL_NO_CONFIG_KHR;
+ }
+ return config;
}
void EglManager::initExtensions() {
@@ -144,12 +224,8 @@ void EglManager::initExtensions() {
EglExtensions.glColorSpace = extensions.has("EGL_KHR_gl_colorspace");
EglExtensions.noConfigContext = extensions.has("EGL_KHR_no_config_context");
EglExtensions.pixelFormatFloat = extensions.has("EGL_EXT_pixel_format_float");
-#ifdef ANDROID_ENABLE_LINEAR_BLENDING
- EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb_linear");
-#else
EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
-#endif
- EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3");
+ EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3_passthrough");
EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
}
@@ -160,77 +236,35 @@ bool EglManager::hasEglContext() {
void EglManager::loadConfigs() {
ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior));
- EGLint swapBehavior =
- (mSwapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
// Note: The default pixel format is RGBA_8888, when other formats are
// available, we should check the target pixel format and configure the
// attributes list properly.
- EGLint attribs[] = {EGL_RENDERABLE_TYPE,
- EGL_OPENGL_ES2_BIT,
- EGL_RED_SIZE,
- 8,
- EGL_GREEN_SIZE,
- 8,
- EGL_BLUE_SIZE,
- 8,
- EGL_ALPHA_SIZE,
- 8,
- EGL_DEPTH_SIZE,
- 0,
- EGL_CONFIG_CAVEAT,
- EGL_NONE,
- EGL_STENCIL_SIZE,
- STENCIL_BUFFER_SIZE,
- EGL_SURFACE_TYPE,
- EGL_WINDOW_BIT | swapBehavior,
- EGL_NONE};
-
- EGLint numConfigs = 1;
- if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, numConfigs, &numConfigs) ||
- numConfigs != 1) {
+ mEglConfig = load8BitsConfig(mEglDisplay, mSwapBehavior);
+ if (mEglConfig == EGL_NO_CONFIG_KHR) {
if (mSwapBehavior == SwapBehavior::Preserved) {
// Try again without dirty regions enabled
ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
mSwapBehavior = SwapBehavior::Discard;
- loadConfigs();
- return; // the call to loadConfigs() we just made picks the wide gamut config
+ ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior));
+ mEglConfig = load8BitsConfig(mEglDisplay, mSwapBehavior);
} else {
// Failed to get a valid config
LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString());
}
}
+ SkColorType wideColorType = DeviceInfo::get()->getWideColorType();
- if (EglExtensions.pixelFormatFloat) {
- // If we reached this point, we have a valid swap behavior
- EGLint attribs16F[] = {EGL_RENDERABLE_TYPE,
- EGL_OPENGL_ES2_BIT,
- EGL_COLOR_COMPONENT_TYPE_EXT,
- EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
- EGL_RED_SIZE,
- 16,
- EGL_GREEN_SIZE,
- 16,
- EGL_BLUE_SIZE,
- 16,
- EGL_ALPHA_SIZE,
- 16,
- EGL_DEPTH_SIZE,
- 0,
- EGL_STENCIL_SIZE,
- STENCIL_BUFFER_SIZE,
- EGL_SURFACE_TYPE,
- EGL_WINDOW_BIT | swapBehavior,
- EGL_NONE};
-
- numConfigs = 1;
- if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs,
- &numConfigs) ||
- numConfigs != 1) {
+ // When we reach this point, we have a valid swap behavior
+ if (wideColorType == SkColorType::kRGBA_F16_SkColorType && EglExtensions.pixelFormatFloat) {
+ mEglConfigWideGamut = loadFP16Config(mEglDisplay, mSwapBehavior);
+ if (mEglConfigWideGamut == EGL_NO_CONFIG_KHR) {
ALOGE("Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
EglExtensions.pixelFormatFloat = false;
}
+ } else if (wideColorType == SkColorType::kN32_SkColorType) {
+ mEglConfigWideGamut = load8BitsConfig(mEglDisplay, mSwapBehavior);
}
}
@@ -261,11 +295,12 @@ void EglManager::createPBufferSurface() {
}
}
-Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window, ColorMode colorMode) {
+Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
+ ColorMode colorMode,
+ SkColorSpace::Gamut colorGamut) {
LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
- bool wideColorGamut = colorMode == ColorMode::WideColorGamut && EglExtensions.glColorSpace &&
- EglExtensions.scRGB && EglExtensions.pixelFormatFloat &&
+ bool wideColorGamut = colorMode == ColorMode::WideColorGamut && mHasWideColorGamutSupport &&
EglExtensions.noConfigContext;
// The color space we want to use depends on whether linear blending is turned
@@ -283,8 +318,8 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
// When wide gamut rendering is on we cannot rely on the GPU performing
// linear blending for us. We use two different color spaces to tag the
// surface appropriately for SurfaceFlinger:
- // - Gamma blending (default) requires the use of the scRGB-nl color space
- // - Linear blending requires the use of the scRGB color space
+ // - Gamma blending (default) requires the use of the non-linear color space
+ // - Linear blending requires the use of the linear color space
// Not all Android targets support the EGL_GL_COLORSPACE_KHR extension
// We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value.
@@ -294,19 +329,20 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
if (EglExtensions.glColorSpace) {
attribs[0] = EGL_GL_COLORSPACE_KHR;
-#ifdef ANDROID_ENABLE_LINEAR_BLENDING
- if (wideColorGamut) {
- attribs[1] = EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT;
- } else {
- attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR;
- }
-#else
if (wideColorGamut) {
- attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
+ switch (colorGamut) {
+ case SkColorSpace::Gamut::kDCIP3_D65_Gamut:
+ attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
+ break;
+ case SkColorSpace::Gamut::kSRGB_Gamut:
+ attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ }
} else {
attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
}
-#endif
}
EGLSurface surface = eglCreateWindowSurface(
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 2a44f7e10b80..4dd90961b4f7 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -48,7 +48,8 @@ public:
bool hasEglContext();
- Result<EGLSurface, EGLint> createSurface(EGLNativeWindowType window, ColorMode colorMode);
+ Result<EGLSurface, EGLint> createSurface(EGLNativeWindowType window, ColorMode colorMode,
+ SkColorSpace::Gamut colorGamut);
void destroySurface(EGLSurface surface);
void destroy();
@@ -80,6 +81,14 @@ public:
status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence);
private:
+ enum class SwapBehavior {
+ Discard,
+ Preserved,
+ BufferAge,
+ };
+
+ static EGLConfig load8BitsConfig(EGLDisplay display, SwapBehavior swapBehavior);
+ static EGLConfig loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior);
void initExtensions();
void createPBufferSurface();
@@ -93,12 +102,7 @@ private:
EGLContext mEglContext;
EGLSurface mPBufferSurface;
EGLSurface mCurrentSurface;
-
- enum class SwapBehavior {
- Discard,
- Preserved,
- BufferAge,
- };
+ bool mHasWideColorGamutSupport;
SwapBehavior mSwapBehavior = SwapBehavior::Discard;
};
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 4972554c65cc..42e17b273bee 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -28,9 +28,9 @@
class GrContext;
-namespace android {
+struct ANativeWindow;
-class Surface;
+namespace android {
namespace uirenderer {
@@ -67,7 +67,7 @@ public:
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
- virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
+ virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
virtual void onStop() = 0;
virtual bool isSurfaceReady() = 0;
virtual bool isContextReady() = 0;
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
new file mode 100644
index 000000000000..6f2b9df918e3
--- /dev/null
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -0,0 +1,318 @@
+/*
+ * 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.
+ */
+
+#include "ReliableSurface.h"
+
+#include <private/android/AHardwareBufferHelpers.h>
+
+namespace android::uirenderer::renderthread {
+
+// TODO: Re-enable after addressing more of the TODO's
+// With this disabled we won't have a good up-front signal that the surface is no longer valid,
+// however we can at least handle that reactively post-draw. There's just not a good mechanism
+// to propagate this error back to the caller
+constexpr bool DISABLE_BUFFER_PREFETCH = true;
+
+// TODO: Make surface less protected
+// This exists because perform is a varargs, and ANativeWindow has no va_list perform.
+// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do
+// that instead
+struct SurfaceExposer : Surface {
+ // Make warnings happy
+ SurfaceExposer() = delete;
+
+ using Surface::setBufferCount;
+ using Surface::setSwapInterval;
+ using Surface::dequeueBuffer;
+ using Surface::queueBuffer;
+ using Surface::cancelBuffer;
+ using Surface::lockBuffer_DEPRECATED;
+ using Surface::perform;
+};
+
+#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__)
+
+ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) {
+ LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr");
+
+ ANativeWindow::setSwapInterval = hook_setSwapInterval;
+ ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
+ ANativeWindow::cancelBuffer = hook_cancelBuffer;
+ ANativeWindow::queueBuffer = hook_queueBuffer;
+ ANativeWindow::query = hook_query;
+ ANativeWindow::perform = hook_perform;
+
+ ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
+ ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
+ ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
+ ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
+}
+
+ReliableSurface::~ReliableSurface() {
+ clearReservedBuffer();
+}
+
+void ReliableSurface::perform(int operation, va_list args) {
+ std::lock_guard _lock{mMutex};
+
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ mUsage = va_arg(args, uint32_t);
+ break;
+ case NATIVE_WINDOW_SET_USAGE64:
+ mUsage = va_arg(args, uint64_t);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+ /* width */ va_arg(args, uint32_t);
+ /* height */ va_arg(args, uint32_t);
+ mFormat = va_arg(args, PixelFormat);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ mFormat = va_arg(args, PixelFormat);
+ break;
+ }
+}
+
+int ReliableSurface::reserveNext() {
+ {
+ std::lock_guard _lock{mMutex};
+ if (mReservedBuffer) {
+ ALOGW("reserveNext called but there was already a buffer reserved?");
+ return OK;
+ }
+ if (mInErrorState) {
+ return UNKNOWN_ERROR;
+ }
+ if (mHasDequeuedBuffer) {
+ return OK;
+ }
+ if constexpr (DISABLE_BUFFER_PREFETCH) {
+ return OK;
+ }
+ }
+
+ // TODO: Update this to better handle when requested dimensions have changed
+ // Currently the driver does this via query + perform but that's after we've already
+ // reserved a buffer. Should we do that logic instead? Or should we drop
+ // the backing Surface to the ground and go full manual on the IGraphicBufferProducer instead?
+
+ int fenceFd = -1;
+ ANativeWindowBuffer* buffer = nullptr;
+ int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd);
+
+ {
+ std::lock_guard _lock{mMutex};
+ LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext");
+ mReservedBuffer = buffer;
+ mReservedFenceFd.reset(fenceFd);
+ }
+
+ return result;
+}
+
+void ReliableSurface::clearReservedBuffer() {
+ ANativeWindowBuffer* buffer = nullptr;
+ int releaseFd = -1;
+ {
+ std::lock_guard _lock{mMutex};
+ if (mReservedBuffer) {
+ ALOGW("Reserved buffer %p was never used", mReservedBuffer);
+ buffer = mReservedBuffer;
+ releaseFd = mReservedFenceFd.release();
+ }
+ mReservedBuffer = nullptr;
+ mReservedFenceFd.reset();
+ mHasDequeuedBuffer = false;
+ }
+ if (buffer) {
+ callProtected(mSurface, cancelBuffer, buffer, releaseFd);
+ }
+}
+
+int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
+ clearReservedBuffer();
+ if (isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+ int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd);
+ return result;
+}
+
+int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) {
+ {
+ std::lock_guard _lock{mMutex};
+ if (mReservedBuffer) {
+ *buffer = mReservedBuffer;
+ *fenceFd = mReservedFenceFd.release();
+ mReservedBuffer = nullptr;
+ return OK;
+ }
+ }
+
+ int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
+ if (result != OK) {
+ ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
+ *buffer = acquireFallbackBuffer();
+ *fenceFd = -1;
+ return *buffer ? OK : INVALID_OPERATION;
+ } else {
+ std::lock_guard _lock{mMutex};
+ mHasDequeuedBuffer = true;
+ }
+ return OK;
+}
+
+int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
+ clearReservedBuffer();
+
+ if (isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+
+ int result = callProtected(mSurface, queueBuffer, buffer, fenceFd);
+ return result;
+}
+
+bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
+ if (!mScratchBuffer || !windowBuffer) {
+ return false;
+ }
+ ANativeWindowBuffer* scratchBuffer =
+ AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
+ return windowBuffer == scratchBuffer;
+}
+
+ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() {
+ std::lock_guard _lock{mMutex};
+ mInErrorState = true;
+
+ if (mScratchBuffer) {
+ return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
+ }
+
+ AHardwareBuffer_Desc desc;
+ desc.usage = mUsage;
+ desc.format = mFormat;
+ desc.width = 1;
+ desc.height = 1;
+ desc.layers = 1;
+ desc.rfu0 = 0;
+ desc.rfu1 = 0;
+ AHardwareBuffer* newBuffer = nullptr;
+ int err = AHardwareBuffer_allocate(&desc, &newBuffer);
+ if (err) {
+ // Allocate failed, that sucks
+ ALOGW("Failed to allocate scratch buffer, error=%d", err);
+ return nullptr;
+ }
+ mScratchBuffer.reset(newBuffer);
+ return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
+}
+
+Surface* ReliableSurface::getWrapped(const ANativeWindow* window) {
+ return getSelf(window)->mSurface.get();
+}
+
+int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) {
+ return callProtected(getWrapped(window), setSwapInterval, interval);
+}
+
+int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd) {
+ return getSelf(window)->dequeueBuffer(buffer, fenceFd);
+}
+
+int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd) {
+ return getSelf(window)->cancelBuffer(buffer, fenceFd);
+}
+
+int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd) {
+ return getSelf(window)->queueBuffer(buffer, fenceFd);
+}
+
+int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer** buffer) {
+ ANativeWindowBuffer* buf;
+ int fenceFd = -1;
+ int result = window->dequeueBuffer(window, &buf, &fenceFd);
+ if (result != OK) {
+ return result;
+ }
+ sp<Fence> fence(new Fence(fenceFd));
+ int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
+ if (waitResult != OK) {
+ ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult);
+ window->cancelBuffer(window, buf, -1);
+ return waitResult;
+ }
+ *buffer = buf;
+ return result;
+}
+
+int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ return window->cancelBuffer(window, buffer, -1);
+}
+
+int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ // This method is a no-op in Surface as well
+ return OK;
+}
+
+int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ return window->queueBuffer(window, buffer, -1);
+}
+
+int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) {
+ return getWrapped(window)->query(what, value);
+}
+
+int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) {
+ // Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions
+ // TODO: Filter to things that only affect the reserved buffer
+ // TODO: Can we mutate the reserved buffer in some cases?
+ getSelf(window)->clearReservedBuffer();
+ va_list args;
+ va_start(args, operation);
+ int result = callProtected(getWrapped(window), perform, operation, args);
+ va_end(args);
+
+ switch (operation) {
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ case NATIVE_WINDOW_SET_USAGE:
+ case NATIVE_WINDOW_SET_USAGE64:
+ va_start(args, operation);
+ getSelf(window)->perform(operation, args);
+ va_end(args);
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+}; // namespace android::uirenderer::renderthread \ No newline at end of file
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
new file mode 100644
index 000000000000..0bfc72ef61cb
--- /dev/null
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gui/Surface.h>
+#include <utils/Macros.h>
+#include <utils/StrongPointer.h>
+
+#include <memory>
+
+namespace android::uirenderer::renderthread {
+
+class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> {
+ PREVENT_COPY_AND_ASSIGN(ReliableSurface);
+
+public:
+ ReliableSurface(sp<Surface>&& surface);
+ ~ReliableSurface();
+
+ void setDequeueTimeout(nsecs_t timeout) { mSurface->setDequeueTimeout(timeout); }
+
+ int reserveNext();
+
+ void allocateBuffers() { mSurface->allocateBuffers(); }
+
+ int query(int what, int* value) const { return mSurface->query(what, value); }
+
+ nsecs_t getLastDequeueStartTime() const { return mSurface->getLastDequeueStartTime(); }
+
+ uint64_t getNextFrameNumber() const { return mSurface->getNextFrameNumber(); }
+
+private:
+ const sp<Surface> mSurface;
+
+ mutable std::mutex mMutex;
+
+ uint64_t mUsage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
+ PixelFormat mFormat = PIXEL_FORMAT_RGBA_8888;
+ std::unique_ptr<AHardwareBuffer, void (*)(AHardwareBuffer*)> mScratchBuffer{
+ nullptr, AHardwareBuffer_release};
+ ANativeWindowBuffer* mReservedBuffer = nullptr;
+ base::unique_fd mReservedFenceFd;
+ bool mHasDequeuedBuffer = false;
+ bool mInErrorState = false;
+
+ bool isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const;
+ ANativeWindowBuffer* acquireFallbackBuffer();
+ void clearReservedBuffer();
+
+ void perform(int operation, va_list args);
+ int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+ int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
+ int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+
+ static Surface* getWrapped(const ANativeWindow*);
+
+ // ANativeWindow hooks
+ static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+ static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd);
+ static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+
+ static int hook_perform(ANativeWindow* window, int operation, ...);
+ static int hook_query(const ANativeWindow* window, int what, int* value);
+ static int hook_setSwapInterval(ANativeWindow* window, int interval);
+
+ static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+};
+
+}; // namespace android::uirenderer::renderthread \ No newline at end of file
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 085812a00f71..aa6af23d8ed3 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -30,6 +30,7 @@
#include "renderthread/RenderThread.h"
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
+#include "WebViewFunctorManager.h"
#include <ui/GraphicBuffer.h>
@@ -143,6 +144,14 @@ void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
}
}
+void RenderProxy::destroyFunctor(int functor) {
+ ATRACE_CALL();
+ RenderThread& thread = RenderThread::getInstance();
+ thread.queue().post([=]() {
+ WebViewFunctorManager::instance().destroyFunctor(functor);
+ });
+}
+
DeferredLayerUpdater* RenderProxy::createTextureLayer() {
return mRenderThread.queue().runSync([this]() -> auto {
return mContext->createTextureLayer();
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d9b789f28f8d..9dc918121be6 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -82,6 +82,7 @@ public:
ANDROID_API void destroy();
ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
+ static void destroyFunctor(int functor);
ANDROID_API DeferredLayerUpdater* createTextureLayer();
ANDROID_API void buildLayer(RenderNode* node);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 207673c1c8dd..c06faddf7fa6 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -132,6 +132,7 @@ RenderThread::RenderThread()
, mFrameCallbackTaskPending(false)
, mRenderState(nullptr)
, mEglManager(nullptr)
+ , mFunctorManager(WebViewFunctorManager::instance())
, mVkManager(nullptr) {
Properties::load();
start("RenderThread");
@@ -197,11 +198,13 @@ void RenderThread::requireGlContext() {
setGrContext(grContext);
}
-void RenderThread::destroyGlContext() {
+void RenderThread::destroyRenderingContext() {
+ mFunctorManager.onContextDestroyed();
if (mEglManager->hasEglContext()) {
setGrContext(nullptr);
mEglManager->destroy();
}
+ vulkanManager().destroy();
}
void RenderThread::dumpGraphicsMemory(int fd) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 2384f9541ec0..5272227509c8 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -23,6 +23,7 @@
#include "CacheManager.h"
#include "TimeLord.h"
#include "thread/ThreadBase.h"
+#include "WebViewFunctorManager.h"
#include <GrContext.h>
#include <SkBitmap.h>
@@ -104,7 +105,7 @@ public:
void dumpGraphicsMemory(int fd);
void requireGlContext();
- void destroyGlContext();
+ void destroyRenderingContext();
/**
* isCurrent provides a way to query, if the caller is running on
@@ -122,6 +123,7 @@ private:
friend class RenderProxy;
friend class DummyVsyncSource;
friend class android::uirenderer::TestUtils;
+ friend class android::uirenderer::WebViewFunctor;
RenderThread();
virtual ~RenderThread();
@@ -151,6 +153,7 @@ private:
TimeLord mTimeLord;
RenderState* mRenderState;
EglManager* mEglManager;
+ WebViewFunctorManager& mFunctorManager;
ProfileDataContainer mGlobalProfileData;
Readback* mReadback = nullptr;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 9a6df75fedd9..aa7a141f6da3 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -472,8 +472,11 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface** surfaceOut) {
window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight);
if (windowWidth != surface->mWindowWidth || windowHeight != surface->mWindowHeight) {
ColorMode colorMode = surface->mColorMode;
+ sk_sp<SkColorSpace> colorSpace = surface->mColorSpace;
+ SkColorSpace::Gamut colorGamut = surface->mColorGamut;
+ SkColorType colorType = surface->mColorType;
destroySurface(surface);
- *surfaceOut = createSurface(window, colorMode);
+ *surfaceOut = createSurface(window, colorMode, colorSpace, colorGamut, colorType);
surface = *surfaceOut;
}
@@ -646,8 +649,7 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt
VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
mRenderThread.getGrContext(), backendRT, kTopLeft_GrSurfaceOrigin,
- surface->mColorMode == ColorMode::WideColorGamut ? kRGBA_F16_SkColorType
- : kRGBA_8888_SkColorType, nullptr, &props);
+ surface->mColorType, surface->mColorSpace, &props);
}
SkASSERT(mCommandPool != VK_NULL_HANDLE);
@@ -744,7 +746,7 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
surface->mWindowWidth = extent.width;
surface->mWindowHeight = extent.height;
- uint32_t imageCount = caps.minImageCount + 2;
+ uint32_t imageCount = std::max<uint32_t>(3, caps.minImageCount);
if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
// Application must settle for fewer images than desired:
imageCount = caps.maxImageCount;
@@ -766,10 +768,20 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
VkFormat surfaceFormat = VK_FORMAT_R8G8B8A8_UNORM;
VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
- if (surface->mColorMode == ColorMode::WideColorGamut) {
+ if (surface->mColorType == SkColorType::kRGBA_F16_SkColorType) {
surfaceFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
- colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
}
+
+ if (surface->mColorMode == ColorMode::WideColorGamut) {
+ if (surface->mColorGamut == SkColorSpace::Gamut::kSRGB_Gamut) {
+ colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
+ } else if (surface->mColorGamut == SkColorSpace::Gamut::kDCIP3_D65_Gamut) {
+ colorSpace = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT;
+ } else {
+ LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ }
+ }
+
bool foundSurfaceFormat = false;
for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
if (surfaceFormat == surfaceFormats[i].format
@@ -830,17 +842,26 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
createBuffers(surface, surfaceFormat, extent);
+ // The window content is not updated (frozen) until a buffer of the window size is received.
+ // This prevents temporary stretching of the window after it is resized, but before the first
+ // buffer with new size is enqueued.
+ native_window_set_scaling_mode(surface->mNativeWindow, NATIVE_WINDOW_SCALING_MODE_FREEZE);
+
return true;
}
-VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode) {
+VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
+ sk_sp<SkColorSpace> surfaceColorSpace,
+ SkColorSpace::Gamut surfaceColorGamut,
+ SkColorType surfaceColorType) {
initialize();
if (!window) {
return nullptr;
}
- VulkanSurface* surface = new VulkanSurface(colorMode, window);
+ VulkanSurface* surface = new VulkanSurface(colorMode, window, surfaceColorSpace,
+ surfaceColorGamut, surfaceColorType);
VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 8594a1bd4339..9eb942c9d6ee 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -38,8 +38,10 @@ class RenderThread;
class VulkanSurface {
public:
- VulkanSurface(ColorMode colorMode, ANativeWindow* window)
- : mColorMode(colorMode), mNativeWindow(window) {}
+ VulkanSurface(ColorMode colorMode, ANativeWindow* window, sk_sp<SkColorSpace> colorSpace,
+ SkColorSpace::Gamut colorGamut, SkColorType colorType)
+ : mColorMode(colorMode), mNativeWindow(window), mColorSpace(colorSpace),
+ mColorGamut(colorGamut), mColorType(colorType) {}
sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
@@ -79,6 +81,9 @@ private:
ANativeWindow* mNativeWindow;
int mWindowWidth = 0;
int mWindowHeight = 0;
+ sk_sp<SkColorSpace> mColorSpace;
+ SkColorSpace::Gamut mColorGamut;
+ SkColorType mColorType;
};
// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
@@ -96,7 +101,10 @@ public:
// Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new
// VulkanSurface object which is returned.
- VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode);
+ VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
+ sk_sp<SkColorSpace> surfaceColorSpace,
+ SkColorSpace::Gamut surfaceColorGamut,
+ SkColorType surfaceColorType);
// Destroy the VulkanSurface and all associated vulkan objects.
void destroySurface(VulkanSurface* surface);
@@ -152,6 +160,7 @@ private:
fPtr = ptr;
return *this;
}
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator FNPTR_TYPE() const { return fPtr; }
private:
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index 3d50d2d7e59c..8a16b2077f6f 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -48,7 +48,7 @@ static void dumpAsTextToFd(protos::GraphicsStatsProto* proto, int outFd);
class FileDescriptor {
public:
- FileDescriptor(int fd) : mFd(fd) {}
+ explicit FileDescriptor(int fd) : mFd(fd) {}
~FileDescriptor() {
if (mFd != -1) {
close(mFd);
@@ -56,7 +56,7 @@ public:
}
}
bool valid() { return mFd != -1; }
- operator int() { return mFd; }
+ operator int() { return mFd; } // NOLINT(google-explicit-constructor)
private:
int mFd;
@@ -64,7 +64,7 @@ private:
class FileOutputStreamLite : public io::ZeroCopyOutputStream {
public:
- FileOutputStreamLite(int fd) : mCopyAdapter(fd), mImpl(&mCopyAdapter) {}
+ explicit FileOutputStreamLite(int fd) : mCopyAdapter(fd), mImpl(&mCopyAdapter) {}
virtual ~FileOutputStreamLite() {}
int GetErrno() { return mCopyAdapter.mErrno; }
@@ -82,7 +82,7 @@ private:
int mFd;
int mErrno = 0;
- FDAdapter(int fd) : mFd(fd) {}
+ explicit FDAdapter(int fd) : mFd(fd) {}
virtual ~FDAdapter() {}
virtual bool Write(const void* buffer, int size) override {
@@ -139,6 +139,7 @@ bool GraphicsStatsService::parseFromFile(const std::string& path,
uint32_t file_version = *reinterpret_cast<uint32_t*>(addr);
if (file_version != sCurrentFileVersion) {
ALOGW("file_version mismatch! expected %d got %d", sCurrentFileVersion, file_version);
+ munmap(addr, sb.st_size);
return false;
}
@@ -150,6 +151,7 @@ bool GraphicsStatsService::parseFromFile(const std::string& path,
ALOGW("Parse failed on '%s' error='%s'", path.c_str(),
output->InitializationErrorString().c_str());
}
+ munmap(addr, sb.st_size);
return success;
}
diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp
index 15aec9f291a4..4a2f57e344c4 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.cpp
+++ b/libs/hwui/surfacetexture/ImageConsumer.cpp
@@ -70,7 +70,8 @@ sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
int slot = st.mCurrentTexture;
if (slot != BufferItem::INVALID_BUFFER_SLOT) {
*queueEmpty = true;
- mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace);
+ mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer,
+ st.mCurrentDataSpace);
return mImageSlots[slot].mImage;
}
}
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 8a1bc4d2f7f2..16a27598c56a 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -32,6 +32,8 @@
namespace android {
namespace uirenderer {
+std::unordered_map<int, TestUtils::CallCounts> TestUtils::sMockFunctorCounts{};
+
SkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end) {
int startA = (start >> 24) & 0xff;
int startR = (start >> 16) & 0xff;
@@ -80,23 +82,21 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint
float y) {
auto utf16 = asciiToUtf16(text);
uint32_t length = strlen(text);
- SkPaint glyphPaint(paint);
- glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- canvas->drawText(
- utf16.get(), length, // text buffer
- 0, length, // draw range
- 0, length, // context range
- x, y, minikin::Bidi::LTR,
- glyphPaint, nullptr, nullptr /* measured text */);
+ Paint glyphPaint(paint);
+ glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding);
+ canvas->drawText(utf16.get(), length, // text buffer
+ 0, length, // draw range
+ 0, length, // context range
+ x, y, minikin::Bidi::LTR, glyphPaint, nullptr, nullptr /* measured text */);
}
void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
const SkPath& path) {
auto utf16 = asciiToUtf16(text);
- SkPaint glyphPaint(paint);
- glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ Paint glyphPaint(paint);
+ glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding);
canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, glyphPaint,
- nullptr);
+ nullptr);
}
void TestUtils::TestTask::run() {
@@ -110,11 +110,7 @@ void TestUtils::TestTask::run() {
rtCallback(renderThread);
- if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- renderThread.vulkanManager().destroy();
- } else {
- renderThread.destroyGlContext();
- }
+ renderThread.destroyRenderingContext();
}
std::unique_ptr<uint16_t[]> TestUtils::asciiToUtf16(const char* str) {
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index c5db861d4f48..6a1ca5a25361 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -27,6 +27,7 @@
#include <renderstate/RenderState.h>
#include <renderthread/RenderThread.h>
+#include <gtest/gtest.h>
#include <memory>
namespace android {
@@ -201,8 +202,7 @@ public:
static void recordNode(RenderNode& node, std::function<void(Canvas&)> contentCallback) {
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- node.stagingProperties().getWidth(), node.stagingProperties().getHeight(),
- &node));
+ node.stagingProperties().getWidth(), node.stagingProperties().getHeight(), &node));
contentCallback(*canvas.get());
node.setStagingDisplayList(canvas->finishRecording());
}
@@ -267,7 +267,14 @@ public:
renderthread::RenderThread::getInstance().queue().runSync([&]() { task.run(); });
}
+ static void runOnRenderThreadUnmanaged(RtCallback rtCallback) {
+ auto& rt = renderthread::RenderThread::getInstance();
+ rt.queue().runSync([&]() { rtCallback(rt); });
+ }
+
+
static bool isRenderThreadRunning() { return renderthread::RenderThread::hasInstance(); }
+ static pid_t getRenderThreadTid() { return renderthread::RenderThread::getInstance().getTid(); }
static SkColor interpolateColor(float fraction, SkColor start, SkColor end);
@@ -296,7 +303,52 @@ public:
static SkRect getClipBounds(const SkCanvas* canvas);
static SkRect getLocalClipBounds(const SkCanvas* canvas);
+ struct CallCounts {
+ int sync = 0;
+ int contextDestroyed = 0;
+ int destroyed = 0;
+ int glesDraw = 0;
+ };
+
+ static void expectOnRenderThread() { EXPECT_EQ(gettid(), TestUtils::getRenderThreadTid()); }
+
+ static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) {
+ auto callbacks = WebViewFunctorCallbacks{
+ .onSync =
+ [](int functor, void* client_data, const WebViewSyncData& data) {
+ expectOnRenderThread();
+ sMockFunctorCounts[functor].sync++;
+ },
+ .onContextDestroyed =
+ [](int functor, void* client_data) {
+ expectOnRenderThread();
+ sMockFunctorCounts[functor].contextDestroyed++;
+ },
+ .onDestroyed =
+ [](int functor, void* client_data) {
+ expectOnRenderThread();
+ sMockFunctorCounts[functor].destroyed++;
+ },
+ };
+ switch (mode) {
+ case RenderMode::OpenGL_ES:
+ callbacks.gles.draw = [](int functor, void* client_data, const DrawGlInfo& params) {
+ expectOnRenderThread();
+ sMockFunctorCounts[functor].glesDraw++;
+ };
+ break;
+ default:
+ ADD_FAILURE();
+ return WebViewFunctorCallbacks{};
+ }
+ return callbacks;
+ }
+
+ static CallCounts& countsForFunctor(int functor) { return sMockFunctorCounts[functor]; }
+
private:
+ static std::unordered_map<int, CallCounts> sMockFunctorCounts;
+
static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
MarkAndSweepRemoved observer(nullptr);
node->syncProperties();
@@ -306,9 +358,9 @@ private:
}
auto displayList = node->getDisplayList();
if (displayList) {
- for (auto&& childDr : static_cast<skiapipeline::SkiaDisplayList*>(
- const_cast<DisplayList*>(displayList))
- ->mChildNodes) {
+ for (auto&& childDr :
+ static_cast<skiapipeline::SkiaDisplayList*>(const_cast<DisplayList*>(displayList))
+ ->mChildNodes) {
syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode());
}
}
diff --git a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
index 1d3d60716d68..5af7d43d7f66 100644
--- a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
@@ -31,7 +31,7 @@ static bool _BitmapFillrate(
class BitmapFillrate : public TestScene {
public:
- BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TestScene(), mAllocator(allocator) {}
void createContent(int width, int height, Canvas& canvas) override {
@@ -70,4 +70,4 @@ private:
BitmapAllocationTestUtils::BitmapAllocator mAllocator;
std::vector<sp<RenderNode> > mNodes;
-}; \ No newline at end of file
+};
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index ad11a1d32310..510766073b08 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -26,7 +26,7 @@ static bool _BitmapShaders(BitmapAllocationTestUtils::registerBitmapAllocationSc
class BitmapShaders : public TestScene {
public:
- BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TestScene(), mAllocator(allocator) {}
sp<RenderNode> card;
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 448408d19eb1..ec81f629ee45 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -50,7 +50,7 @@ public:
pixels[4000 + 4 * i + 3] = 255;
}
buffer->unlock();
- sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer));
+ sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer, SkColorSpace::MakeSRGB()));
sk_sp<SkShader> hardwareShader(createBitmapShader(*hardwareBitmap));
SkPoint center;
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index 9a1ee54bff49..4111bd24847e 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -16,7 +16,7 @@
#include "TestSceneBase.h"
#include "tests/common/TestListViewSceneBase.h"
-
+#include <SkFont.h>
#include <cstdio>
class ListViewAnimation;
@@ -46,11 +46,13 @@ class ListViewAnimation : public TestListViewSceneBase {
SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor) <
128 * 3;
paint.setColor(bgDark ? Color::White : Color::Grey_700);
- paint.setTextSize(size / 2);
+
+ SkFont font;
+ font.setSize(size / 2);
char charToShow = 'A' + (rand() % 26);
- const SkPoint pos[] = {{SkIntToScalar(size / 2),
- /*approximate centering*/ SkFloatToScalar(size * 0.7f)}};
- canvas.drawPosText(&charToShow, 1, pos, paint);
+ const SkPoint pos = {SkIntToScalar(size / 2),
+ /*approximate centering*/ SkFloatToScalar(size * 0.7f)};
+ canvas.drawSimpleText(&charToShow, 1, kUTF8_SkTextEncoding, pos.fX, pos.fY, font, paint);
return bitmap;
}
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index 0d87776e083e..d189a9379c33 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -76,7 +76,7 @@ public:
paint.setStrokeWidth(strokeWidth);
// fill column with each op
int middleCount = canvas.save(SaveFlags::MatrixClip);
- for (auto op : ops) {
+ for (const auto& op : ops) {
int innerCount = canvas.save(SaveFlags::MatrixClip);
canvas.clipRect(0, 0, cellSize, cellSize, SkClipOp::kIntersect);
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index a64e8444a9b1..286f5f194aed 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -48,7 +48,7 @@ static bool _TvAppNoRoundedCornerColorFilter(
class TvApp : public TestScene {
public:
- TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TestScene(), mAllocator(allocator) {}
sp<RenderNode> mBg;
@@ -232,7 +232,7 @@ private:
class TvAppNoRoundedCorner : public TvApp {
public:
- TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
+ explicit TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
virtual float roundedCornerRadius() override { return dp(0); }
@@ -240,7 +240,7 @@ private:
class TvAppColorFilter : public TvApp {
public:
- TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
+ explicit TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
virtual bool useOverlay() override { return false; }
@@ -248,7 +248,7 @@ private:
class TvAppNoRoundedCornerColorFilter : public TvApp {
public:
- TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
+ explicit TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
: TvApp(allocator) {}
private:
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 524dfb0fe4ef..174a14080eff 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -19,6 +19,8 @@
#include "Properties.h"
#include "hwui/Typeface.h"
+#include "HardwareBitmapUploader.h"
+#include "renderthread/RenderProxy.h"
#include <benchmark/benchmark.h>
#include <getopt.h>
@@ -353,6 +355,9 @@ int main(int argc, char* argv[]) {
gBenchmarkReporter->Finalize();
}
+ renderthread::RenderProxy::trimMemory(100);
+ HardwareBitmapUploader::terminate();
+
LeakChecker::checkForLeaks();
return 0;
}
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index a6869791a915..f4c3e13b0ea6 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -19,9 +19,9 @@
#include "tests/common/TestUtils.h"
-#include <gtest/gtest.h>
#include <SkBitmap.h>
#include <SkImage.h>
+#include <gtest/gtest.h>
using namespace android;
using namespace android::uirenderer;
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index 89f0c52b49ec..1723c2eb4948 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -30,22 +30,6 @@ public:
void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) {
ADD_FAILURE() << "onDrawDRRect not expected in this test";
}
- void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint& paint) {
- ADD_FAILURE() << "onDrawText not expected in this test";
- }
- void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint& paint) {
- ADD_FAILURE() << "onDrawPosText not expected in this test";
- }
- void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- ADD_FAILURE() << "onDrawPosTextH not expected in this test";
- }
- void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[],
- const SkRect* cullRect, const SkPaint& paint) {
- ADD_FAILURE() << "onDrawTextRSXform not expected in this test";
- }
void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) {
ADD_FAILURE() << "onDrawTextBlob not expected in this test";
}
@@ -128,4 +112,4 @@ public:
int mDrawCounter = 0; // counts how may draw calls of any kind were made to this canvas
};
-} \ No newline at end of file
+}
diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
index 08b967964c59..dac888cd79ca 100644
--- a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
+++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
@@ -39,7 +39,7 @@ public:
// current thread can spoof being a GPU thread
static void destroyEglContext() {
if (TestUtils::isRenderThreadRunning()) {
- TestUtils::runOnRenderThread([](RenderThread& thread) { thread.destroyGlContext(); });
+ TestUtils::runOnRenderThread([](RenderThread& thread) { thread.destroyRenderingContext(); });
}
}
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 0331581799b7..c813cd945905 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -355,9 +355,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) {
class ProjectionTestCanvas : public SkCanvas {
public:
ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
- void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
- mDrawCounter++;
- }
+ void onDrawRect(const SkRect& rect, const SkPaint& paint) override { mDrawCounter++; }
int getDrawCounter() { return mDrawCounter; }
@@ -370,7 +368,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) {
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
properties.setProjectionReceiver(true);
},
- "B"); // a receiver with an empty display list
+ "B"); // a receiver with an empty display list
auto projectingRipple = TestUtils::createSkiaNode(
0, 0, 100, 100,
@@ -389,14 +387,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) {
canvas.drawRenderNode(projectingRipple.get());
},
"C");
- auto parent = TestUtils::createSkiaNode(
- 0, 0, 100, 100,
- [&receiverBackground, &child](RenderProperties& properties,
- SkiaRecordingCanvas& canvas) {
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- },
- "A");
+ auto parent =
+ TestUtils::createSkiaNode(0, 0, 100, 100,
+ [&receiverBackground, &child](RenderProperties& properties,
+ SkiaRecordingCanvas& canvas) {
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ },
+ "A");
ContextFactory contextFactory;
std::unique_ptr<CanvasContext> canvasContext(
CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
@@ -1058,7 +1056,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
public:
FrameTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) override {
+ const SkPaint* paint, SrcRectConstraint constraint) override {
mDrawCounter++;
EXPECT_EQ(kLow_SkFilterQuality, paint->getFilterQuality());
}
@@ -1076,7 +1074,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
FrameTestCanvas canvas;
RenderNodeDrawable drawable(layerNode.get(), &canvas, true);
canvas.drawDrawable(&drawable);
- EXPECT_EQ(1, canvas.mDrawCounter); //make sure the layer was composed
+ EXPECT_EQ(1, canvas.mDrawCounter); // make sure the layer was composed
// clean up layer pointer, so we can safely destruct RenderNode
layerNode->setLayerSurface(nullptr);
@@ -1129,15 +1127,14 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
getTotalMatrix());
} else {
// Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
- EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y),
- matrix);
- EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y),
- getTotalMatrix());
+ EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), matrix);
+ EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), getTotalMatrix());
}
}
protected:
int mDrawCounter = 0;
+
private:
bool mFirstDidConcat = true;
};
@@ -1174,14 +1171,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
public:
VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) override {
+ const SkPaint* paint, SrcRectConstraint constraint) override {
const int index = mDrawCounter++;
switch (index) {
case 0:
EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
break;
case 1:
- EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH/2, CANVAS_HEIGHT));
+ EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT));
break;
default:
ADD_FAILURE();
@@ -1191,17 +1188,18 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
VectorDrawable::Group* group = new VectorDrawable::Group();
sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
- vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH/10, CANVAS_HEIGHT/10);
+ vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH / 10, CANVAS_HEIGHT / 10);
- auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
- [&](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH,
- CANVAS_HEIGHT));
- canvas.drawVectorDrawable(vectorDrawable.get());
- vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH/2,
- CANVAS_HEIGHT));
- canvas.drawVectorDrawable(vectorDrawable.get());
- });
+ auto node =
+ TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ [&](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ vectorDrawable->mutateStagingProperties()->setBounds(
+ SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
+ canvas.drawVectorDrawable(vectorDrawable.get());
+ vectorDrawable->mutateStagingProperties()->setBounds(
+ SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT));
+ canvas.drawVectorDrawable(vectorDrawable.get());
+ });
VectorDrawableTestCanvas canvas;
RenderNodeDrawable drawable(node.get(), &canvas, true);
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index a6073ebb5c74..1cd9bd8ee9d9 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -295,7 +295,8 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
canvasContext->destroy();
}
-RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
+// TODO: Is this supposed to work in SkiaGL/SkiaVK?
+RENDERTHREAD_TEST(DISABLED_RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
VectorDrawable::Group* group = new VectorDrawable::Group();
sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
@@ -306,6 +307,7 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
ContextFactory contextFactory;
std::unique_ptr<CanvasContext> canvasContext(
CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
+ canvasContext->setSurface(nullptr);
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
LayerUpdateQueue layerUpdateQueue;
diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp
index 1433aa0349f4..87981f115763 100644
--- a/libs/hwui/tests/unit/ShaderCacheTests.cpp
+++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-#include <dirent.h>
#include <cutils/properties.h>
-#include <cstdint>
+#include <dirent.h>
#include <errno.h>
+#include <gtest/gtest.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <utils/Log.h>
-#include "pipeline/skia/ShaderCache.h"
+#include <cstdint>
#include "FileBlobCache.h"
+#include "pipeline/skia/ShaderCache.h"
using namespace android::uirenderer::skiapipeline;
@@ -66,7 +66,6 @@ public:
} /* namespace uirenderer */
} /* namespace android */
-
namespace {
std::string getExternalStorageFolder() {
@@ -82,14 +81,12 @@ bool folderExist(const std::string& folderName) {
return false;
}
-inline bool
-checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) {
- return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size()
- && 0 == memcmp(shader1->data(), shader2->data(), shader1->size());
+inline bool checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) {
+ return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() &&
+ 0 == memcmp(shader1->data(), shader2->data(), shader1->size());
}
-inline bool
-checkShader(const sk_sp<SkData>& shader, const char* program) {
+inline bool checkShader(const sk_sp<SkData>& shader, const char* program) {
sk_sp<SkData> shader2 = SkData::MakeWithCString(program);
return checkShader(shader, shader2);
}
@@ -116,32 +113,31 @@ void genRandomData(std::vector<T>& buffer) {
}
}
-
#define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get())
TEST(ShaderCacheTest, testWriteAndRead) {
if (!folderExist(getExternalStorageFolder())) {
- //don't run the test if external storage folder is not available
+ // don't run the test if external storage folder is not available
return;
}
- std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
- std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
+ std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
+ std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
- //remove any test files from previous test run
+ // remove any test files from previous test run
int deleteFile = remove(cacheFile1.c_str());
ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
std::srand(0);
- //read the cache from a file that does not exist
+ // read the cache from a file that does not exist
ShaderCache::get().setFilename(cacheFile1.c_str());
- ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save
+ ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save
ShaderCache::get().initShaderDiskCache();
- //read a key - should not be found since the cache is empty
+ // read a key - should not be found since the cache is empty
sk_sp<SkData> outVS;
ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
- //write to the in-memory cache without storing on disk and verify we read the same values
+ // write to the in-memory cache without storing on disk and verify we read the same values
sk_sp<SkData> inVS;
setShader(inVS, "sassas");
ShaderCache::get().store(GrProgramDescTest(100), *inVS.get());
@@ -152,23 +148,23 @@ TEST(ShaderCacheTest, testWriteAndRead) {
ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
ASSERT_TRUE(checkShader(outVS, "someVS"));
- //store content to disk and release in-memory cache
+ // store content to disk and release in-memory cache
ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
- //change to a file that does not exist and verify load fails
+ // change to a file that does not exist and verify load fails
ShaderCache::get().setFilename(cacheFile2.c_str());
ShaderCache::get().initShaderDiskCache();
ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
- //load again content from disk from an existing file and check the data is read correctly
+ // load again content from disk from an existing file and check the data is read correctly
ShaderCache::get().setFilename(cacheFile1.c_str());
ShaderCache::get().initShaderDiskCache();
sk_sp<SkData> outVS2;
ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
ASSERT_TRUE(checkShader(outVS2, "someVS"));
- //change data, store to disk, read back again and verify data has been changed
+ // change data, store to disk, read back again and verify data has been changed
setShader(inVS, "ewData1");
ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
@@ -176,9 +172,8 @@ TEST(ShaderCacheTest, testWriteAndRead) {
ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
ASSERT_TRUE(checkShader(outVS2, "ewData1"));
-
- //write and read big data chunk (50K)
- size_t dataSize = 50*1024;
+ // write and read big data chunk (50K)
+ size_t dataSize = 50 * 1024;
std::vector<uint8_t> dataBuffer(dataSize);
genRandomData(dataBuffer);
setShader(inVS, dataBuffer);
@@ -194,31 +189,31 @@ TEST(ShaderCacheTest, testWriteAndRead) {
TEST(ShaderCacheTest, testCacheValidation) {
if (!folderExist(getExternalStorageFolder())) {
- //don't run the test if external storage folder is not available
+ // don't run the test if external storage folder is not available
return;
}
- std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
- std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
+ std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
+ std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
- //remove any test files from previous test run
+ // remove any test files from previous test run
int deleteFile = remove(cacheFile1.c_str());
ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
std::srand(0);
- //generate identity and read the cache from a file that does not exist
+ // generate identity and read the cache from a file that does not exist
ShaderCache::get().setFilename(cacheFile1.c_str());
- ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save
+ ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save
std::vector<uint8_t> identity(1024);
genRandomData(identity);
- ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() *
- sizeof(decltype(identity)::value_type));
+ ShaderCache::get().initShaderDiskCache(
+ identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
// generate random content in cache and store to disk
constexpr size_t numBlob(10);
constexpr size_t keySize(1024);
constexpr size_t dataSize(50 * 1024);
- std::vector< std::pair<sk_sp<SkData>, sk_sp<SkData>> > blobVec(numBlob);
+ std::vector<std::pair<sk_sp<SkData>, sk_sp<SkData>>> blobVec(numBlob);
for (auto& blob : blobVec) {
std::vector<uint8_t> keyBuffer(keySize);
std::vector<uint8_t> dataBuffer(dataSize);
@@ -237,47 +232,47 @@ TEST(ShaderCacheTest, testCacheValidation) {
// change to a file that does not exist and verify validation fails
ShaderCache::get().setFilename(cacheFile2.c_str());
ShaderCache::get().initShaderDiskCache();
- ASSERT_FALSE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) );
+ ASSERT_FALSE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
// restore the original file and verify validation succeeds
ShaderCache::get().setFilename(cacheFile1.c_str());
- ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() *
- sizeof(decltype(identity)::value_type));
- ASSERT_TRUE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) );
+ ShaderCache::get().initShaderDiskCache(
+ identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
+ ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
for (const auto& blob : blobVec) {
auto outVS = ShaderCache::get().load(*blob.first.get());
- ASSERT_TRUE( checkShader(outVS, blob.second) );
+ ASSERT_TRUE(checkShader(outVS, blob.second));
}
// generate error identity and verify load fails
ShaderCache::get().initShaderDiskCache(identity.data(), -1);
for (const auto& blob : blobVec) {
- ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>() );
+ ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
}
- ShaderCache::get().initShaderDiskCache(nullptr, identity.size() *
- sizeof(decltype(identity)::value_type));
+ ShaderCache::get().initShaderDiskCache(
+ nullptr, identity.size() * sizeof(decltype(identity)::value_type));
for (const auto& blob : blobVec) {
- ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>() );
+ ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
}
// verify the cache validation again after load fails
- ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() *
- sizeof(decltype(identity)::value_type));
- ASSERT_TRUE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) );
+ ShaderCache::get().initShaderDiskCache(
+ identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
+ ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
for (const auto& blob : blobVec) {
auto outVS = ShaderCache::get().load(*blob.first.get());
- ASSERT_TRUE( checkShader(outVS, blob.second) );
+ ASSERT_TRUE(checkShader(outVS, blob.second));
}
// generate another identity and verify load fails
for (auto& data : identity) {
data += std::rand();
}
- ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() *
- sizeof(decltype(identity)::value_type));
+ ShaderCache::get().initShaderDiskCache(
+ identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
for (const auto& blob : blobVec) {
- ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>() );
+ ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
}
ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 415f9e8517ff..1b4cf7e144bd 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -100,16 +100,35 @@ TEST(SkiaDisplayList, syncContexts) {
GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas);
skiaDL.mChildFunctors.push_back(&functorDrawable);
+ int functor2 = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ auto& counts = TestUtils::countsForFunctor(functor2);
+ skiaDL.mChildFunctors.push_back(
+ skiaDL.allocateDrawable<GLFunctorDrawable>(functor2, &dummyCanvas));
+ WebViewFunctor_release(functor2);
+
SkRect bounds = SkRect::MakeWH(200, 200);
VectorDrawableRoot vectorDrawable(new VectorDrawable::Group());
vectorDrawable.mutateStagingProperties()->setBounds(bounds);
skiaDL.mVectorDrawables.push_back(&vectorDrawable);
// ensure that the functor and vectorDrawable are properly synced
- skiaDL.syncContents();
-
- ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync);
- ASSERT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds);
+ TestUtils::runOnRenderThread([&](auto&) {
+ skiaDL.syncContents(WebViewSyncData{
+ .applyForceDark = false,
+ });
+ });
+
+ EXPECT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync);
+ EXPECT_EQ(counts.sync, 1);
+ EXPECT_EQ(counts.destroyed, 0);
+ EXPECT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds);
+
+ skiaDL.reset();
+ TestUtils::runOnRenderThread([](auto&) {
+ // Fence
+ });
+ EXPECT_EQ(counts.destroyed, 1);
}
class ContextFactory : public IContextFactory {
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index d16b8be89e20..3c06dab36fe4 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -24,10 +24,10 @@
#include "DamageAccumulator.h"
#include "IContextFactory.h"
#include "SkiaCanvas.h"
-#include "pipeline/skia/SkiaUtils.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaRecordingCanvas.h"
+#include "pipeline/skia/SkiaUtils.h"
#include "renderthread/CanvasContext.h"
#include "tests/common/TestUtils.h"
@@ -51,8 +51,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
}
@@ -84,8 +83,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) {
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
// drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
}
@@ -106,12 +104,10 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
auto surface = SkSurface::MakeRasterN32Premul(2, 2);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
}
@@ -130,8 +126,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
auto surface = SkSurface::MakeRasterN32Premul(2, 2);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED);
@@ -203,38 +198,32 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) {
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
// Single draw, should be white.
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
// 1 Overdraw, should be blue blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0d0ff);
// 2 Overdraw, should be green blended onto white
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0ffd0);
// 3 Overdraw, should be pink blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffffc0c0);
// 4 Overdraw, should be red blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
// 5 Overdraw, should be red blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
}
@@ -389,7 +378,6 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {
EXPECT_FALSE(pipeline->isSurfaceReady());
EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::SRGB));
EXPECT_TRUE(pipeline->isSurfaceReady());
- renderThread.destroyGlContext();
+ renderThread.destroyRenderingContext();
EXPECT_FALSE(pipeline->isSurfaceReady());
}
-
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 479c462bd1a6..635429dea359 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -44,7 +44,7 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac
static const int CANVAS_HEIGHT = 100;
class PropertyTestCanvas : public TestCanvasBase {
public:
- PropertyTestCanvas(std::function<void(const SkCanvas&)> callback)
+ explicit PropertyTestCanvas(std::function<void(const SkCanvas&)> callback)
: TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT), mCallback(callback) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
EXPECT_EQ(mDrawCounter++, 0);
diff --git a/libs/hwui/tests/unit/ThreadBaseTests.cpp b/libs/hwui/tests/unit/ThreadBaseTests.cpp
index 1168ff211202..817c1f3d3e43 100644
--- a/libs/hwui/tests/unit/ThreadBaseTests.cpp
+++ b/libs/hwui/tests/unit/ThreadBaseTests.cpp
@@ -95,7 +95,7 @@ TEST(ThreadBase, lifecyclePerf) {
};
struct Counter {
- Counter(EventCount* count) : mCount(count) { mCount->construct++; }
+ explicit Counter(EventCount* count) : mCount(count) { mCount->construct++; }
Counter(const Counter& other) : mCount(other.mCount) {
if (mCount) mCount->copy++;
@@ -148,4 +148,4 @@ TEST(ThreadBase, lifecycle) {
ASSERT_EQ(1, dummyObject->getStrongCount());
ASSERT_EQ(2, lifecycleTestHelper(dummyObject));
ASSERT_EQ(1, dummyObject->getStrongCount());
-} \ No newline at end of file
+}
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index b645aeb55074..1a09b1c52d8a 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -54,9 +54,9 @@ std::shared_ptr<minikin::FontFamily> buildFamily(const char* fileName) {
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
sk_sp<SkTypeface> typeface(fm->makeFromStream(std::move(fontData)));
LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", fileName);
- std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
- std::move(typeface), data, st.st_size, fileName, 0,
- std::vector<minikin::FontVariation>());
+ std::shared_ptr<minikin::MinikinFont> font =
+ std::make_shared<MinikinFontSkia>(std::move(typeface), data, st.st_size, fileName, 0,
+ std::vector<minikin::FontVariation>());
std::vector<minikin::Font> fonts;
fonts.push_back(minikin::Font::Builder(font).build());
return std::make_shared<minikin::FontFamily>(std::move(fonts));
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index ee6beba847a0..5db002862fcd 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -85,8 +85,10 @@ const static TestData sTestDataSet[] = {
outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0);
outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0);
- outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0, 10.0);
- outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0, 20.0);
+ outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0,
+ 10.0);
+ outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0,
+ 20.0);
}},
// Check box VectorDrawable path data
@@ -157,7 +159,8 @@ const static TestData sTestDataSet[] = {
},
[](SkPath* outPath) {
outPath->moveTo(300.0, 70.0);
- outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction, 301.0, 70.0);
+ outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction,
+ 301.0, 70.0);
outPath->close();
outPath->moveTo(300.0, 70.0);
}},
@@ -236,14 +239,14 @@ struct StringPath {
};
const StringPath sStringPaths[] = {
- {"3e...3", false}, // Not starting with a verb and ill-formatted float
- {"L.M.F.A.O", false}, // No floats following verbs
- {"m 1 1", true}, // Valid path data
- {"\n \t z", true}, // Valid path data with leading spaces
- {"1-2e34567", false}, // Not starting with a verb and ill-formatted float
- {"f 4 5", false}, // Invalid verb
- {"\r ", false}, // Empty string
- {"L1,0 L1,1 L0,1 z M1000", false} // Not enough floats following verb M.
+ {"3e...3", false}, // Not starting with a verb and ill-formatted float
+ {"L.M.F.A.O", false}, // No floats following verbs
+ {"m 1 1", true}, // Valid path data
+ {"\n \t z", true}, // Valid path data with leading spaces
+ {"1-2e34567", false}, // Not starting with a verb and ill-formatted float
+ {"f 4 5", false}, // Invalid verb
+ {"\r ", false}, // Empty string
+ {"L1,0 L1,1 L0,1 z M1000", false} // Not enough floats following verb M.
};
static bool hasSameVerbs(const PathData& from, const PathData& to) {
@@ -251,7 +254,7 @@ static bool hasSameVerbs(const PathData& from, const PathData& to) {
}
TEST(PathParser, parseStringForData) {
- for (TestData testData : sTestDataSet) {
+ for (const TestData& testData : sTestDataSet) {
PathParser::ParseResult result;
// Test generated path data against the given data.
PathData pathData;
@@ -271,7 +274,7 @@ TEST(PathParser, parseStringForData) {
}
TEST(VectorDrawableUtils, createSkPathFromPathData) {
- for (TestData testData : sTestDataSet) {
+ for (const TestData& testData : sTestDataSet) {
SkPath expectedPath;
testData.skPathLamda(&expectedPath);
SkPath actualPath;
@@ -281,7 +284,7 @@ TEST(VectorDrawableUtils, createSkPathFromPathData) {
}
TEST(PathParser, parseAsciiStringForSkPath) {
- for (TestData testData : sTestDataSet) {
+ for (const TestData& testData : sTestDataSet) {
PathParser::ParseResult result;
size_t length = strlen(testData.pathString);
// Check the return value as well as the SkPath generated.
@@ -304,8 +307,8 @@ TEST(PathParser, parseAsciiStringForSkPath) {
}
TEST(VectorDrawableUtils, morphPathData) {
- for (TestData fromData : sTestDataSet) {
- for (TestData toData : sTestDataSet) {
+ for (const TestData& fromData : sTestDataSet) {
+ for (const TestData& toData : sTestDataSet) {
bool canMorph = VectorDrawableUtils::canMorph(fromData.pathData, toData.pathData);
if (fromData.pathData == toData.pathData) {
EXPECT_TRUE(canMorph);
@@ -319,8 +322,8 @@ TEST(VectorDrawableUtils, morphPathData) {
TEST(VectorDrawableUtils, interpolatePathData) {
// Interpolate path data with itself and every other path data
- for (TestData fromData : sTestDataSet) {
- for (TestData toData : sTestDataSet) {
+ for (const TestData& fromData : sTestDataSet) {
+ for (const TestData& toData : sTestDataSet) {
PathData outData;
bool success = VectorDrawableUtils::interpolatePathData(&outData, fromData.pathData,
toData.pathData, 0.5);
@@ -331,7 +334,7 @@ TEST(VectorDrawableUtils, interpolatePathData) {
float fractions[] = {0, 0.00001, 0.28, 0.5, 0.7777, 0.9999999, 1};
// Now try to interpolate with a slightly modified version of self and expect success
- for (TestData fromData : sTestDataSet) {
+ for (const TestData& fromData : sTestDataSet) {
PathData toPathData = fromData.pathData;
for (size_t i = 0; i < toPathData.points.size(); i++) {
toPathData.points[i]++;
diff --git a/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
new file mode 100644
index 000000000000..e1fb8b7069ff
--- /dev/null
+++ b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "WebViewFunctorManager.h"
+#include "private/hwui/WebViewFunctor.h"
+#include "renderthread/RenderProxy.h"
+#include "tests/common/TestUtils.h"
+
+#include <unordered_map>
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(WebViewFunctor, createDestroyGLES) {
+ int functor = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ ASSERT_NE(-1, functor);
+ WebViewFunctor_release(functor);
+ TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) {
+ // Empty, don't care
+ });
+ auto& counts = TestUtils::countsForFunctor(functor);
+ // We never initialized, so contextDestroyed == 0
+ EXPECT_EQ(0, counts.contextDestroyed);
+ EXPECT_EQ(1, counts.destroyed);
+}
+
+TEST(WebViewFunctor, createSyncHandleGLES) {
+ int functor = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ ASSERT_NE(-1, functor);
+ auto handle = WebViewFunctorManager::instance().handleFor(functor);
+ ASSERT_TRUE(handle);
+ WebViewFunctor_release(functor);
+ EXPECT_FALSE(WebViewFunctorManager::instance().handleFor(functor));
+ TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) {
+ // fence
+ });
+ auto& counts = TestUtils::countsForFunctor(functor);
+ EXPECT_EQ(0, counts.sync);
+ EXPECT_EQ(0, counts.contextDestroyed);
+ EXPECT_EQ(0, counts.destroyed);
+
+ TestUtils::runOnRenderThreadUnmanaged([&](auto&) {
+ WebViewSyncData syncData;
+ handle->sync(syncData);
+ });
+
+ EXPECT_EQ(1, counts.sync);
+
+ TestUtils::runOnRenderThreadUnmanaged([&](auto&) {
+ WebViewSyncData syncData;
+ handle->sync(syncData);
+ });
+
+ EXPECT_EQ(2, counts.sync);
+
+ handle.clear();
+
+ TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) {
+ // fence
+ });
+
+ EXPECT_EQ(2, counts.sync);
+ EXPECT_EQ(0, counts.contextDestroyed);
+ EXPECT_EQ(1, counts.destroyed);
+}
+
+TEST(WebViewFunctor, createSyncDrawGLES) {
+ int functor = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ ASSERT_NE(-1, functor);
+ auto handle = WebViewFunctorManager::instance().handleFor(functor);
+ ASSERT_TRUE(handle);
+ WebViewFunctor_release(functor);
+ auto& counts = TestUtils::countsForFunctor(functor);
+ for (int i = 0; i < 5; i++) {
+ TestUtils::runOnRenderThreadUnmanaged([&](auto&) {
+ WebViewSyncData syncData;
+ handle->sync(syncData);
+ DrawGlInfo drawInfo;
+ handle->drawGl(drawInfo);
+ handle->drawGl(drawInfo);
+ });
+ }
+ handle.clear();
+ TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) {
+ // fence
+ });
+ EXPECT_EQ(5, counts.sync);
+ EXPECT_EQ(10, counts.glesDraw);
+ EXPECT_EQ(1, counts.contextDestroyed);
+ EXPECT_EQ(1, counts.destroyed);
+}
+
+TEST(WebViewFunctor, contextDestroyed) {
+ int functor = WebViewFunctor_create(
+ nullptr, TestUtils::createMockFunctor(RenderMode::OpenGL_ES), RenderMode::OpenGL_ES);
+ ASSERT_NE(-1, functor);
+ auto handle = WebViewFunctorManager::instance().handleFor(functor);
+ ASSERT_TRUE(handle);
+ WebViewFunctor_release(functor);
+ auto& counts = TestUtils::countsForFunctor(functor);
+ TestUtils::runOnRenderThreadUnmanaged([&](auto&) {
+ WebViewSyncData syncData;
+ handle->sync(syncData);
+ DrawGlInfo drawInfo;
+ handle->drawGl(drawInfo);
+ });
+ EXPECT_EQ(1, counts.sync);
+ EXPECT_EQ(1, counts.glesDraw);
+ EXPECT_EQ(0, counts.contextDestroyed);
+ EXPECT_EQ(0, counts.destroyed);
+ TestUtils::runOnRenderThreadUnmanaged([](auto& rt) {
+ rt.destroyRenderingContext();
+ });
+ EXPECT_EQ(1, counts.sync);
+ EXPECT_EQ(1, counts.glesDraw);
+ EXPECT_EQ(1, counts.contextDestroyed);
+ EXPECT_EQ(0, counts.destroyed);
+ TestUtils::runOnRenderThreadUnmanaged([&](auto&) {
+ WebViewSyncData syncData;
+ handle->sync(syncData);
+ DrawGlInfo drawInfo;
+ handle->drawGl(drawInfo);
+ });
+ EXPECT_EQ(2, counts.sync);
+ EXPECT_EQ(2, counts.glesDraw);
+ EXPECT_EQ(1, counts.contextDestroyed);
+ EXPECT_EQ(0, counts.destroyed);
+ handle.clear();
+ TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) {
+ // fence
+ });
+ EXPECT_EQ(2, counts.sync);
+ EXPECT_EQ(2, counts.glesDraw);
+ EXPECT_EQ(2, counts.contextDestroyed);
+ EXPECT_EQ(1, counts.destroyed);
+}
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
index aecceb3609f5..63d15403b607 100644
--- a/libs/hwui/tests/unit/main.cpp
+++ b/libs/hwui/tests/unit/main.cpp
@@ -17,14 +17,14 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "Properties.h"
#include "debug/GlesDriver.h"
#include "debug/NullGlesDriver.h"
#include "hwui/Typeface.h"
-#include "Properties.h"
#include "tests/common/LeakChecker.h"
-#include "thread/TaskProcessor.h"
#include "thread/Task.h"
#include "thread/TaskManager.h"
+#include "thread/TaskProcessor.h"
#include <signal.h>
diff --git a/libs/hwui/thread/ThreadBase.h b/libs/hwui/thread/ThreadBase.h
index f9de8a5037e5..8cdcc46b97fb 100644
--- a/libs/hwui/thread/ThreadBase.h
+++ b/libs/hwui/thread/ThreadBase.h
@@ -27,7 +27,7 @@
namespace android::uirenderer {
-class ThreadBase : protected Thread {
+class ThreadBase : public Thread {
PREVENT_COPY_AND_ASSIGN(ThreadBase);
public:
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 4daccda78e23..4473ce632b1b 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -17,6 +17,7 @@
#define COLOR_H
#include <math.h>
+#include <cutils/compiler.h>
#include <system/graphics.h>
#include <ui/PixelFormat.h>
@@ -117,7 +118,7 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
-sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
+ANDROID_API sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
struct Lab {
float L;
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index b401fcf58f76..9c4a1be4b269 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -168,7 +168,7 @@ public:
};
// enable allocators to be constructed from other templated types
template <class U>
- LinearStdAllocator(const LinearStdAllocator<U>& other) // NOLINT(implicit)
+ LinearStdAllocator(const LinearStdAllocator<U>& other) // NOLINT(google-explicit-constructor)
: linearAllocator(other.linearAllocator) {}
T* allocate(size_t num, const void* = 0) {
diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include/android/os/IncidentReportArgs.h
index c56f689b7419..ee1e33c43b89 100644
--- a/libs/incident/include/android/os/IncidentReportArgs.h
+++ b/libs/incident/include/android/os/IncidentReportArgs.h
@@ -40,7 +40,7 @@ const uint8_t DEST_AUTOMATIC = 200;
class IncidentReportArgs : public Parcelable {
public:
IncidentReportArgs();
- explicit IncidentReportArgs(const IncidentReportArgs& that);
+ IncidentReportArgs(const IncidentReportArgs& that);
virtual ~IncidentReportArgs();
virtual status_t writeToParcel(Parcel* out) const;
diff --git a/libs/incident/proto/android/os/metadata.proto b/libs/incident/proto/android/os/metadata.proto
index f8f4e36b1e89..3b0e9c9aa17a 100644
--- a/libs/incident/proto/android/os/metadata.proto
+++ b/libs/incident/proto/android/os/metadata.proto
@@ -61,8 +61,10 @@ message IncidentMetadata {
optional bool timed_out = 7;
// true if the section is truncated.
optional bool is_truncated = 8;
+ // message for debugging if there is an error.
+ optional string error_msg = 9;
- // Next Tag: 9
+ // Next Tag: 10;
}
repeated SectionStats sections = 6;
diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp
index fbc21e558806..26261ef929ae 100644
--- a/libs/incident/src/IncidentReportArgs.cpp
+++ b/libs/incident/src/IncidentReportArgs.cpp
@@ -18,7 +18,7 @@
#include <android/os/IncidentReportArgs.h>
-#include <cutils/log.h>
+#include <log/log.h>
namespace android {
namespace os {
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index f1d9397783ed..89d3cc4f5083 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -14,7 +14,6 @@
cc_library_shared {
name: "libinputservice",
-
srcs: [
"PointerController.cpp",
"SpriteController.cpp",
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 0a90f85cda0e..b4f19c99c6fe 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -39,7 +39,7 @@ protected:
virtual ~WeakLooperCallback() { }
public:
- WeakLooperCallback(const wp<LooperCallback>& callback) :
+ explicit WeakLooperCallback(const wp<LooperCallback>& callback) :
mCallback(callback) {
}
@@ -89,10 +89,6 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
mLocked.animationPending = false;
- mLocked.displayWidth = -1;
- mLocked.displayHeight = -1;
- mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
-
mLocked.presentation = PRESENTATION_POINTER;
mLocked.presentationChanged = false;
@@ -110,15 +106,6 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
mLocked.lastFrameUpdatedTime = 0;
mLocked.buttonState = 0;
-
- mPolicy->loadPointerIcon(&mLocked.pointerIcon);
-
- loadResources();
-
- if (mLocked.pointerIcon.isValid()) {
- mLocked.pointerIconChanged = true;
- updatePointerLocked();
- }
}
PointerController::~PointerController() {
@@ -144,23 +131,15 @@ bool PointerController::getBounds(float* outMinX, float* outMinY,
bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
float* outMaxX, float* outMaxY) const {
- if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
+
+ if (!mLocked.viewport.isValid()) {
return false;
}
- *outMinX = 0;
- *outMinY = 0;
- switch (mLocked.displayOrientation) {
- case DISPLAY_ORIENTATION_90:
- case DISPLAY_ORIENTATION_270:
- *outMaxX = mLocked.displayHeight - 1;
- *outMaxY = mLocked.displayWidth - 1;
- break;
- default:
- *outMaxX = mLocked.displayWidth - 1;
- *outMaxY = mLocked.displayHeight - 1;
- break;
- }
+ *outMinX = mLocked.viewport.logicalLeft;
+ *outMinY = mLocked.viewport.logicalTop;
+ *outMaxX = mLocked.viewport.logicalRight - 1;
+ *outMaxY = mLocked.viewport.logicalBottom - 1;
return true;
}
@@ -231,6 +210,12 @@ void PointerController::getPosition(float* outX, float* outY) const {
*outY = mLocked.pointerY;
}
+int32_t PointerController::getDisplayId() const {
+ AutoMutex _l(mLock);
+
+ return mLocked.viewport.displayId;
+}
+
void PointerController::fade(Transition transition) {
AutoMutex _l(mLock);
@@ -355,48 +340,56 @@ void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout
void PointerController::reloadPointerResources() {
AutoMutex _l(mLock);
- loadResources();
+ loadResourcesLocked();
+ updatePointerLocked();
+}
- if (mLocked.presentation == PRESENTATION_POINTER) {
- mLocked.additionalMouseResources.clear();
- mLocked.animationResources.clear();
- mPolicy->loadPointerIcon(&mLocked.pointerIcon);
- mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
- &mLocked.animationResources);
- }
+/**
+ * The viewport values for deviceHeight and deviceWidth have already been adjusted for rotation,
+ * so here we are getting the dimensions in the original, unrotated orientation (orientation 0).
+ */
+static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, int32_t& height) {
+ width = viewport.deviceWidth;
+ height = viewport.deviceHeight;
- mLocked.presentationChanged = true;
- updatePointerLocked();
+ if (viewport.orientation == DISPLAY_ORIENTATION_90
+ || viewport.orientation == DISPLAY_ORIENTATION_270) {
+ std::swap(width, height);
+ }
}
-void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) {
+void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
AutoMutex _l(mLock);
-
- // Adjust to use the display's unrotated coordinate frame.
- if (orientation == DISPLAY_ORIENTATION_90
- || orientation == DISPLAY_ORIENTATION_270) {
- int32_t temp = height;
- height = width;
- width = temp;
+ if (viewport == mLocked.viewport) {
+ return;
}
- if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
- mLocked.displayWidth = width;
- mLocked.displayHeight = height;
+ const DisplayViewport oldViewport = mLocked.viewport;
+ mLocked.viewport = viewport;
+
+ int32_t oldDisplayWidth, oldDisplayHeight;
+ getNonRotatedSize(oldViewport, oldDisplayWidth, oldDisplayHeight);
+ int32_t newDisplayWidth, newDisplayHeight;
+ getNonRotatedSize(viewport, newDisplayWidth, newDisplayHeight);
+
+ // Reset cursor position to center if size or display changed.
+ if (oldViewport.displayId != viewport.displayId
+ || oldDisplayWidth != newDisplayWidth
+ || oldDisplayHeight != newDisplayHeight) {
float minX, minY, maxX, maxY;
if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
mLocked.pointerX = (minX + maxX) * 0.5f;
mLocked.pointerY = (minY + maxY) * 0.5f;
+ // Reload icon resources for density may be changed.
+ loadResourcesLocked();
} else {
mLocked.pointerX = 0;
mLocked.pointerY = 0;
}
fadeOutAndReleaseAllSpotsLocked();
- }
-
- if (mLocked.displayOrientation != orientation) {
+ } else if (oldViewport.orientation != viewport.orientation) {
// Apply offsets to convert from the pixel top-left corner position to the pixel center.
// This creates an invariant frame of reference that we can easily rotate when
// taking into account that the pointer may be located at fractional pixel offsets.
@@ -405,37 +398,37 @@ void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_
float temp;
// Undo the previous rotation.
- switch (mLocked.displayOrientation) {
+ switch (oldViewport.orientation) {
case DISPLAY_ORIENTATION_90:
temp = x;
- x = mLocked.displayWidth - y;
+ x = oldViewport.deviceHeight - y;
y = temp;
break;
case DISPLAY_ORIENTATION_180:
- x = mLocked.displayWidth - x;
- y = mLocked.displayHeight - y;
+ x = oldViewport.deviceWidth - x;
+ y = oldViewport.deviceHeight - y;
break;
case DISPLAY_ORIENTATION_270:
temp = x;
x = y;
- y = mLocked.displayHeight - temp;
+ y = oldViewport.deviceWidth - temp;
break;
}
// Perform the new rotation.
- switch (orientation) {
+ switch (viewport.orientation) {
case DISPLAY_ORIENTATION_90:
temp = x;
x = y;
- y = mLocked.displayWidth - temp;
+ y = viewport.deviceHeight - temp;
break;
case DISPLAY_ORIENTATION_180:
- x = mLocked.displayWidth - x;
- y = mLocked.displayHeight - y;
+ x = viewport.deviceWidth - x;
+ y = viewport.deviceHeight - y;
break;
case DISPLAY_ORIENTATION_270:
temp = x;
- x = mLocked.displayHeight - y;
+ x = viewport.deviceWidth - y;
y = temp;
break;
}
@@ -444,7 +437,6 @@ void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_
// and save the results.
mLocked.pointerX = x - 0.5f;
mLocked.pointerY = y - 0.5f;
- mLocked.displayOrientation = orientation;
}
updatePointerLocked();
@@ -614,11 +606,16 @@ void PointerController::removeInactivityTimeoutLocked() {
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
}
-void PointerController::updatePointerLocked() {
+void PointerController::updatePointerLocked() REQUIRES(mLock) {
+ if (!mLocked.viewport.isValid()) {
+ return;
+ }
+
mSpriteController->openTransaction();
mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
+ mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId);
if (mLocked.pointerAlpha > 0) {
mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
@@ -729,8 +726,18 @@ void PointerController::fadeOutAndReleaseAllSpotsLocked() {
}
}
-void PointerController::loadResources() {
+void PointerController::loadResourcesLocked() REQUIRES(mLock) {
mPolicy->loadPointerResources(&mResources);
+
+ if (mLocked.presentation == PRESENTATION_POINTER) {
+ mLocked.additionalMouseResources.clear();
+ mLocked.animationResources.clear();
+ mPolicy->loadPointerIcon(&mLocked.pointerIcon);
+ mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
+ &mLocked.animationResources);
+ }
+
+ mLocked.pointerIconChanged = true;
}
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 7f4e5a59c9b6..a32cc42a3342 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -23,6 +23,7 @@
#include <vector>
#include <ui/DisplayInfo.h>
+#include <input/DisplayViewport.h>
#include <input/Input.h>
#include <PointerControllerInterface.h>
#include <utils/BitSet.h>
@@ -96,6 +97,7 @@ public:
virtual int32_t getButtonState() const;
virtual void setPosition(float x, float y);
virtual void getPosition(float* outX, float* outY) const;
+ virtual int32_t getDisplayId() const;
virtual void fade(Transition transition);
virtual void unfade(Transition transition);
@@ -106,7 +108,7 @@ public:
void updatePointerIcon(int32_t iconId);
void setCustomPointerIcon(const SpriteIcon& icon);
- void setDisplayViewport(int32_t width, int32_t height, int32_t orientation);
+ void setDisplayViewport(const DisplayViewport& viewport);
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void reloadPointerResources();
@@ -156,9 +158,7 @@ private:
size_t animationFrameIndex;
nsecs_t lastFrameUpdatedTime;
- int32_t displayWidth;
- int32_t displayHeight;
- int32_t displayOrientation;
+ DisplayViewport viewport;
InactivityTimeout inactivityTimeout;
@@ -182,7 +182,7 @@ private:
Vector<Spot*> spots;
Vector<sp<Sprite> > recycledSprites;
- } mLocked;
+ } mLocked GUARDED_BY(mLock);
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
void setPositionLocked(float x, float y);
@@ -207,7 +207,7 @@ private:
void fadeOutAndReleaseSpotLocked(Spot* spot);
void fadeOutAndReleaseAllSpotsLocked();
- void loadResources();
+ void loadResourcesLocked();
};
} // namespace android
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index eb2bc98ec9e9..c1868d3a94d6 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -144,13 +144,16 @@ void SpriteController::doUpdateSprites() {
}
}
- // Resize sprites if needed.
+ // Resize and/or reparent sprites if needed.
SurfaceComposerClient::Transaction t;
bool needApplyTransaction = false;
for (size_t i = 0; i < numSprites; i++) {
SpriteUpdate& update = updates.editItemAt(i);
+ if (update.state.surfaceControl == nullptr) {
+ continue;
+ }
- if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
+ if (update.state.wantSurfaceVisible()) {
int32_t desiredWidth = update.state.icon.bitmap.width();
int32_t desiredHeight = update.state.icon.bitmap.height();
if (update.state.surfaceWidth < desiredWidth
@@ -170,6 +173,12 @@ void SpriteController::doUpdateSprites() {
}
}
}
+
+ // If surface is a new one, we have to set right layer stack.
+ if (update.surfaceChanged || update.state.dirty & DIRTY_DISPLAY_ID) {
+ t.setLayerStack(update.state.surfaceControl, update.state.displayId);
+ needApplyTransaction = true;
+ }
}
if (needApplyTransaction) {
t.apply();
@@ -236,7 +245,7 @@ void SpriteController::doUpdateSprites() {
if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
|| (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
| DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
- | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
+ | DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID))))) {
needApplyTransaction = true;
if (wantSurfaceVisibleAndDrawn
@@ -445,6 +454,15 @@ void SpriteController::SpriteImpl::setTransformationMatrix(
}
}
+void SpriteController::SpriteImpl::setDisplayId(int32_t displayId) {
+ AutoMutex _l(mController->mLock);
+
+ if (mLocked.state.displayId != displayId) {
+ mLocked.state.displayId = displayId;
+ invalidateLocked(DIRTY_DISPLAY_ID);
+ }
+}
+
void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
bool wasDirty = mLocked.state.dirty;
mLocked.state.dirty |= dirty;
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 31e43e9b99e5..5b216f50d113 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -125,6 +125,9 @@ public:
/* Sets the sprite transformation matrix. */
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
+
+ /* Sets the id of the display where the sprite should be shown. */
+ virtual void setDisplayId(int32_t displayId) = 0;
};
/*
@@ -170,6 +173,7 @@ private:
DIRTY_LAYER = 1 << 4,
DIRTY_VISIBILITY = 1 << 5,
DIRTY_HOTSPOT = 1 << 6,
+ DIRTY_DISPLAY_ID = 1 << 7,
};
/* Describes the state of a sprite.
@@ -180,7 +184,7 @@ private:
struct SpriteState {
inline SpriteState() :
dirty(0), visible(false),
- positionX(0), positionY(0), layer(0), alpha(1.0f),
+ positionX(0), positionY(0), layer(0), alpha(1.0f), displayId(ADISPLAY_ID_DEFAULT),
surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
}
@@ -193,6 +197,7 @@ private:
int32_t layer;
float alpha;
SpriteTransformationMatrix transformationMatrix;
+ int32_t displayId;
sp<SurfaceControl> surfaceControl;
int32_t surfaceWidth;
@@ -225,6 +230,7 @@ private:
virtual void setLayer(int32_t layer);
virtual void setAlpha(float alpha);
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
+ virtual void setDisplayId(int32_t displayId);
inline const SpriteState& getStateLocked() const {
return mLocked.state;
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
index c84de4c1c083..0b7f6e46be65 100644
--- a/libs/protoutil/include/android/util/EncodedBuffer.h
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -38,13 +38,13 @@ class EncodedBuffer
{
public:
EncodedBuffer();
- EncodedBuffer(size_t chunkSize);
+ explicit EncodedBuffer(size_t chunkSize);
~EncodedBuffer();
class Pointer {
public:
Pointer();
- Pointer(size_t chunkSize);
+ explicit Pointer(size_t chunkSize);
size_t pos() const;
size_t index() const;
@@ -161,7 +161,7 @@ public:
friend class iterator;
class iterator {
public:
- iterator(const EncodedBuffer& buffer);
+ explicit iterator(const EncodedBuffer& buffer);
/**
* Returns the number of bytes written in the buffer