18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci 168bf80f4bSopenharmony_ci 178bf80f4bSopenharmony_ci#include "font_manager.h" 188bf80f4bSopenharmony_ci 198bf80f4bSopenharmony_ci#include <algorithm> 208bf80f4bSopenharmony_ci#include <freetype/ftsizes.h> 218bf80f4bSopenharmony_ci#include <freetype/tttables.h> 228bf80f4bSopenharmony_ci#include <numeric> 238bf80f4bSopenharmony_ci 248bf80f4bSopenharmony_ci#include <base/containers/fixed_string.h> 258bf80f4bSopenharmony_ci#include <base/containers/string.h> 268bf80f4bSopenharmony_ci#include <core/intf_engine.h> 278bf80f4bSopenharmony_ci#include <core/io/intf_file_manager.h> 288bf80f4bSopenharmony_ci#include <core/log.h> 298bf80f4bSopenharmony_ci#include <render/datastore/intf_render_data_store_default_staging.h> 308bf80f4bSopenharmony_ci#include <render/datastore/intf_render_data_store_manager.h> 318bf80f4bSopenharmony_ci#include <render/device/gpu_resource_desc.h> 328bf80f4bSopenharmony_ci#include <render/device/intf_gpu_resource_manager.h> 338bf80f4bSopenharmony_ci#include <render/intf_render_context.h> 348bf80f4bSopenharmony_ci 358bf80f4bSopenharmony_ci#include "face_data.h" 368bf80f4bSopenharmony_ci#include "font.h" 378bf80f4bSopenharmony_ci#include "font_buffer.h" 388bf80f4bSopenharmony_ci 398bf80f4bSopenharmony_ciusing namespace BASE_NS; 408bf80f4bSopenharmony_ciusing namespace BASE_NS::Math; 418bf80f4bSopenharmony_ciusing namespace CORE_NS; 428bf80f4bSopenharmony_ciusing namespace RENDER_NS; 438bf80f4bSopenharmony_ciusing namespace FONT_NS::FontDefs; 448bf80f4bSopenharmony_ci 458bf80f4bSopenharmony_ciFONT_BEGIN_NAMESPACE() 468bf80f4bSopenharmony_ci 478bf80f4bSopenharmony_cinamespace { 488bf80f4bSopenharmony_cistring GetErrorString() 498bf80f4bSopenharmony_ci{ 508bf80f4bSopenharmony_ci // Visual Studio lacks strerrorlen_s so need to define a fixed "large enough" buffer 518bf80f4bSopenharmony_ci char buffer[64u]; 528bf80f4bSopenharmony_ci#ifdef _WIN32 538bf80f4bSopenharmony_ci strerror_s(buffer, sizeof(buffer), errno); 548bf80f4bSopenharmony_ci#else 558bf80f4bSopenharmony_ci strerror_r(errno, buffer, sizeof(buffer)); 568bf80f4bSopenharmony_ci#endif 578bf80f4bSopenharmony_ci return string(buffer); 588bf80f4bSopenharmony_ci} 598bf80f4bSopenharmony_ci 608bf80f4bSopenharmony_ciconstexpr string_view RENDER_DATA_STORE_DEFAULT_STAGING = "RenderDataStoreDefaultStaging"; 618bf80f4bSopenharmony_ci 628bf80f4bSopenharmony_ciconst Width widths_os2_match[] = { Width::UltraCondensed, Width::ExtraCondensed, Width::Condensed, Width::SemiCondensed, 638bf80f4bSopenharmony_ci Width::Normal, Width::SemiExpanded, Width::Expanded, Width::ExtraExpanded, Width::UltraExpanded }; 648bf80f4bSopenharmony_ci 658bf80f4bSopenharmony_ciTypeFace InitTypeFace(FT_Face face, string_view path, string_view filename) 668bf80f4bSopenharmony_ci{ 678bf80f4bSopenharmony_ci TypeFace typeFace { 688bf80f4bSopenharmony_ci string(path), // font file path 698bf80f4bSopenharmony_ci face->family_name, // family name as defined in font file 708bf80f4bSopenharmony_ci face->style_name, // style name as defined in font file 718bf80f4bSopenharmony_ci BASE_NS::hash(filename), // physical PATH hash as map key for font buffers map 728bf80f4bSopenharmony_ci face->face_index, // face index for quick access to face in font file 738bf80f4bSopenharmony_ci Regular, // style 748bf80f4bSopenharmony_ci }; 758bf80f4bSopenharmony_ci TT_OS2* tblOS2 = (TT_OS2*)FT_Get_Sfnt_Table(face, FT_SFNT_OS2); 768bf80f4bSopenharmony_ci if (tblOS2) { 778bf80f4bSopenharmony_ci typeFace.style.Weight = static_cast<Weight>(tblOS2->usWeightClass); 788bf80f4bSopenharmony_ci typeFace.style.Width = widths_os2_match[tblOS2->usWidthClass]; 798bf80f4bSopenharmony_ci } else { 808bf80f4bSopenharmony_ci if (face->style_flags & 0x02) { 818bf80f4bSopenharmony_ci typeFace.style.Weight = Weight::Bold; 828bf80f4bSopenharmony_ci } 838bf80f4bSopenharmony_ci } 848bf80f4bSopenharmony_ci if (face->style_flags & 0x01) { 858bf80f4bSopenharmony_ci typeFace.style.SlantType = SlantType::Italic; 868bf80f4bSopenharmony_ci } 878bf80f4bSopenharmony_ci return typeFace; 888bf80f4bSopenharmony_ci} 898bf80f4bSopenharmony_ci} // namespace 908bf80f4bSopenharmony_ci 918bf80f4bSopenharmony_ciFontManager::FontManager(IRenderContext& context) : renderContext_(context) 928bf80f4bSopenharmony_ci{ 938bf80f4bSopenharmony_ci if (FT_Init_FreeType(&fontLib_)) { 948bf80f4bSopenharmony_ci CORE_LOG_E("failed to init freetype library: %s", GetErrorString().c_str()); 958bf80f4bSopenharmony_ci } 968bf80f4bSopenharmony_ci 978bf80f4bSopenharmony_ci GetTypeFacesByDir(typeFaces_, "fonts://"); 988bf80f4bSopenharmony_ci} 998bf80f4bSopenharmony_ci 1008bf80f4bSopenharmony_ciFontManager::~FontManager() 1018bf80f4bSopenharmony_ci{ 1028bf80f4bSopenharmony_ci FT_Done_FreeType(fontLib_); 1038bf80f4bSopenharmony_ci fontLib_ = nullptr; 1048bf80f4bSopenharmony_ci} 1058bf80f4bSopenharmony_ci 1068bf80f4bSopenharmony_ciarray_view<const TypeFace> FontManager::GetTypeFaces() const 1078bf80f4bSopenharmony_ci{ 1088bf80f4bSopenharmony_ci return typeFaces_; 1098bf80f4bSopenharmony_ci} 1108bf80f4bSopenharmony_ci 1118bf80f4bSopenharmony_ciconst TypeFace* FontManager::GetTypeFace(string_view name, string_view styleName) 1128bf80f4bSopenharmony_ci{ 1138bf80f4bSopenharmony_ci for (auto& typeFace : typeFaces_) { 1148bf80f4bSopenharmony_ci if (typeFace.name == name) { 1158bf80f4bSopenharmony_ci if (styleName.empty() || typeFace.styleName == styleName) { 1168bf80f4bSopenharmony_ci return &typeFace; 1178bf80f4bSopenharmony_ci } 1188bf80f4bSopenharmony_ci } 1198bf80f4bSopenharmony_ci } 1208bf80f4bSopenharmony_ci return nullptr; 1218bf80f4bSopenharmony_ci} 1228bf80f4bSopenharmony_ci 1238bf80f4bSopenharmony_civector<TypeFace> FontManager::GetTypeFaces(const string_view filePath) 1248bf80f4bSopenharmony_ci{ 1258bf80f4bSopenharmony_ci vector<TypeFace> typeFaces; 1268bf80f4bSopenharmony_ci GetTypeFacesByFile(typeFaces, filePath); 1278bf80f4bSopenharmony_ci return typeFaces; 1288bf80f4bSopenharmony_ci} 1298bf80f4bSopenharmony_ci 1308bf80f4bSopenharmony_civector<TypeFace> FontManager::GetTypeFaces(array_view<const string_view> lookupDirs) 1318bf80f4bSopenharmony_ci{ 1328bf80f4bSopenharmony_ci vector<TypeFace> typeFaces; 1338bf80f4bSopenharmony_ci for (const auto& dir : lookupDirs) { 1348bf80f4bSopenharmony_ci GetTypeFacesByDir(typeFaces, dir); 1358bf80f4bSopenharmony_ci } 1368bf80f4bSopenharmony_ci return typeFaces; 1378bf80f4bSopenharmony_ci} 1388bf80f4bSopenharmony_ci 1398bf80f4bSopenharmony_cistd::shared_ptr<FontBuffer> FontManager::CreateFontBuffer(const TypeFace& typeFace) 1408bf80f4bSopenharmony_ci{ 1418bf80f4bSopenharmony_ci { 1428bf80f4bSopenharmony_ci std::shared_lock readerLock(fontBuffersMutex_); 1438bf80f4bSopenharmony_ci 1448bf80f4bSopenharmony_ci if (auto it = fontBuffers_.find(typeFace.uid); it != fontBuffers_.end()) { 1458bf80f4bSopenharmony_ci if (auto fromWeak = it->second.lock()) { 1468bf80f4bSopenharmony_ci return fromWeak; 1478bf80f4bSopenharmony_ci } 1488bf80f4bSopenharmony_ci } 1498bf80f4bSopenharmony_ci } 1508bf80f4bSopenharmony_ci 1518bf80f4bSopenharmony_ci std::lock_guard writerLock(fontBuffersMutex_); 1528bf80f4bSopenharmony_ci 1538bf80f4bSopenharmony_ci if (auto it = fontBuffers_.find(typeFace.uid); it != fontBuffers_.end()) { 1548bf80f4bSopenharmony_ci if (auto fromWeak = it->second.lock()) { 1558bf80f4bSopenharmony_ci return fromWeak; 1568bf80f4bSopenharmony_ci } 1578bf80f4bSopenharmony_ci } 1588bf80f4bSopenharmony_ci 1598bf80f4bSopenharmony_ci auto& fileManager = renderContext_.GetEngine().GetFileManager(); 1608bf80f4bSopenharmony_ci IFile::Ptr file = fileManager.OpenFile(typeFace.path); 1618bf80f4bSopenharmony_ci if (file == nullptr) { 1628bf80f4bSopenharmony_ci CORE_LOG_E("failed to open font %s | %s", typeFace.path.data(), GetErrorString().c_str()); 1638bf80f4bSopenharmony_ci return nullptr; 1648bf80f4bSopenharmony_ci } 1658bf80f4bSopenharmony_ci 1668bf80f4bSopenharmony_ci const size_t len = static_cast<size_t>(file->GetLength()); 1678bf80f4bSopenharmony_ci vector<uint8_t> bytes; 1688bf80f4bSopenharmony_ci bytes.resize(len); 1698bf80f4bSopenharmony_ci 1708bf80f4bSopenharmony_ci if (len != file->Read(bytes.data(), bytes.size())) { 1718bf80f4bSopenharmony_ci CORE_LOG_E("failed to read %zu bytes from %s | %s", len, typeFace.path.data(), GetErrorString().c_str()); 1728bf80f4bSopenharmony_ci return nullptr; 1738bf80f4bSopenharmony_ci } 1748bf80f4bSopenharmony_ci 1758bf80f4bSopenharmony_ci auto fb = std::make_shared<FontBuffer>(this, typeFace.uid, bytes); 1768bf80f4bSopenharmony_ci 1778bf80f4bSopenharmony_ci fontBuffers_.insert({ typeFace.uid, fb }); 1788bf80f4bSopenharmony_ci CORE_LOG_N("create FontBuffer %p", this); 1798bf80f4bSopenharmony_ci 1808bf80f4bSopenharmony_ci return fb; 1818bf80f4bSopenharmony_ci} 1828bf80f4bSopenharmony_ci 1838bf80f4bSopenharmony_ciIFont::Ptr FontManager::CreateFont(const TypeFace& typeFace) 1848bf80f4bSopenharmony_ci{ 1858bf80f4bSopenharmony_ci std::shared_ptr fontBuff = CreateFontBuffer(typeFace); 1868bf80f4bSopenharmony_ci if (!fontBuff) { 1878bf80f4bSopenharmony_ci return nullptr; 1888bf80f4bSopenharmony_ci } 1898bf80f4bSopenharmony_ci std::shared_ptr<FaceData> face = fontBuff->CreateFace(typeFace.index); 1908bf80f4bSopenharmony_ci if (!face) { 1918bf80f4bSopenharmony_ci return nullptr; 1928bf80f4bSopenharmony_ci } 1938bf80f4bSopenharmony_ci Font::Ptr font = Font::Ptr(new Font(std::move(face))); 1948bf80f4bSopenharmony_ci 1958bf80f4bSopenharmony_ci return font; 1968bf80f4bSopenharmony_ci} 1978bf80f4bSopenharmony_ci 1988bf80f4bSopenharmony_ciIFont::Ptr FontManager::CreateFontFromMemory(const TypeFace& typeFace, const BASE_NS::vector<uint8_t>& buffer) 1998bf80f4bSopenharmony_ci{ 2008bf80f4bSopenharmony_ci std::shared_ptr<FontBuffer> fontBuff; 2018bf80f4bSopenharmony_ci { 2028bf80f4bSopenharmony_ci std::shared_lock readerLock(fontBuffersMutex_); 2038bf80f4bSopenharmony_ci if (auto it = fontBuffers_.find(typeFace.uid); it != fontBuffers_.end()) { 2048bf80f4bSopenharmony_ci fontBuff = it->second.lock(); 2058bf80f4bSopenharmony_ci } 2068bf80f4bSopenharmony_ci } 2078bf80f4bSopenharmony_ci if (!fontBuff) { 2088bf80f4bSopenharmony_ci std::lock_guard writerLock(fontBuffersMutex_); 2098bf80f4bSopenharmony_ci if (auto it = fontBuffers_.find(typeFace.uid); it != fontBuffers_.end()) { 2108bf80f4bSopenharmony_ci fontBuff = it->second.lock(); 2118bf80f4bSopenharmony_ci } 2128bf80f4bSopenharmony_ci if (!fontBuff) { 2138bf80f4bSopenharmony_ci fontBuff = std::make_shared<FontBuffer>(this, typeFace.uid, buffer); 2148bf80f4bSopenharmony_ci fontBuffers_.insert({ typeFace.uid, fontBuff }); 2158bf80f4bSopenharmony_ci } 2168bf80f4bSopenharmony_ci } 2178bf80f4bSopenharmony_ci if (!fontBuff) { 2188bf80f4bSopenharmony_ci return {}; 2198bf80f4bSopenharmony_ci } 2208bf80f4bSopenharmony_ci 2218bf80f4bSopenharmony_ci return Font::Ptr(new Font(fontBuff->CreateFace(typeFace.index))); 2228bf80f4bSopenharmony_ci} 2238bf80f4bSopenharmony_ci 2248bf80f4bSopenharmony_ciuint32_t FontManager::GetGlyphIndex(const TypeFace& typeFace, uint32_t code) 2258bf80f4bSopenharmony_ci{ 2268bf80f4bSopenharmony_ci auto fontBuff = CreateFontBuffer(typeFace); 2278bf80f4bSopenharmony_ci if (!fontBuff) { 2288bf80f4bSopenharmony_ci return 0; 2298bf80f4bSopenharmony_ci } 2308bf80f4bSopenharmony_ci auto face = fontBuff->CreateFace(typeFace.index); 2318bf80f4bSopenharmony_ci if (!face) { 2328bf80f4bSopenharmony_ci return 0; 2338bf80f4bSopenharmony_ci } 2348bf80f4bSopenharmony_ci return face->GetGlyphIndex(code); 2358bf80f4bSopenharmony_ci} 2368bf80f4bSopenharmony_ci 2378bf80f4bSopenharmony_civoid FontManager::FlushCaches() 2388bf80f4bSopenharmony_ci{ 2398bf80f4bSopenharmony_ci UploadPending(); 2408bf80f4bSopenharmony_ci std::lock_guard writerLock(atlasMutex_); 2418bf80f4bSopenharmony_ci atlasTextures_.clear(); 2428bf80f4bSopenharmony_ci CORE_LOG_N("atlas textures flush"); 2438bf80f4bSopenharmony_ci} 2448bf80f4bSopenharmony_ci 2458bf80f4bSopenharmony_civoid FontManager::GetTypeFacesByFile(vector<TypeFace>& typeFaces, string_view path) 2468bf80f4bSopenharmony_ci{ 2478bf80f4bSopenharmony_ci auto& fileManager = renderContext_.GetEngine().GetFileManager(); 2488bf80f4bSopenharmony_ci 2498bf80f4bSopenharmony_ci IFile::Ptr file = fileManager.OpenFile(path); 2508bf80f4bSopenharmony_ci if (file == nullptr) { 2518bf80f4bSopenharmony_ci CORE_LOG_E("failed to open font %s | %s", path.data(), GetErrorString().c_str()); 2528bf80f4bSopenharmony_ci return; 2538bf80f4bSopenharmony_ci } 2548bf80f4bSopenharmony_ci 2558bf80f4bSopenharmony_ci auto entry = fileManager.GetEntry(path); 2568bf80f4bSopenharmony_ci const size_t len = static_cast<size_t>(file->GetLength()); 2578bf80f4bSopenharmony_ci vector<uint8_t> buf(len); 2588bf80f4bSopenharmony_ci 2598bf80f4bSopenharmony_ci if (len != file->Read(buf.data(), buf.size())) { 2608bf80f4bSopenharmony_ci CORE_LOG_E("failed to read %zu bytes from %s | %s", len, path.data(), GetErrorString().c_str()); 2618bf80f4bSopenharmony_ci return; 2628bf80f4bSopenharmony_ci } 2638bf80f4bSopenharmony_ci 2648bf80f4bSopenharmony_ci if (buf.empty()) { 2658bf80f4bSopenharmony_ci return; 2668bf80f4bSopenharmony_ci } 2678bf80f4bSopenharmony_ci 2688bf80f4bSopenharmony_ci FT_Long numFaces = 0; 2698bf80f4bSopenharmony_ci FT_Long numInstances = 0; 2708bf80f4bSopenharmony_ci FT_Long faceIndex = 0; 2718bf80f4bSopenharmony_ci FT_Long instanceIndex = 0; 2728bf80f4bSopenharmony_ci 2738bf80f4bSopenharmony_ci constexpr uint8_t INSTANCE_SHIFT = 16u; 2748bf80f4bSopenharmony_ci 2758bf80f4bSopenharmony_ci do { 2768bf80f4bSopenharmony_ci FT_Long faceId = (instanceIndex << INSTANCE_SHIFT) + faceIndex; 2778bf80f4bSopenharmony_ci auto face = OpenFtFace(buf, faceId); 2788bf80f4bSopenharmony_ci // lume api is utf8, unicode is the default charmap with freetype. 2798bf80f4bSopenharmony_ci if (face && face->charmap) { 2808bf80f4bSopenharmony_ci typeFaces.push_back(InitTypeFace(face, path, entry.name)); 2818bf80f4bSopenharmony_ci 2828bf80f4bSopenharmony_ci numFaces = face->num_faces; 2838bf80f4bSopenharmony_ci numInstances = face->style_flags >> INSTANCE_SHIFT; 2848bf80f4bSopenharmony_ci 2858bf80f4bSopenharmony_ci CORE_LOG_N("%s", path.data()); 2868bf80f4bSopenharmony_ci CORE_LOG_N(" number of faces: %ld", numFaces); 2878bf80f4bSopenharmony_ci CORE_LOG_N(" number of instances: %ld", numInstances); 2888bf80f4bSopenharmony_ci 2898bf80f4bSopenharmony_ci if (instanceIndex < numInstances) { 2908bf80f4bSopenharmony_ci ++instanceIndex; 2918bf80f4bSopenharmony_ci } else { 2928bf80f4bSopenharmony_ci ++faceIndex; 2938bf80f4bSopenharmony_ci instanceIndex = 0; 2948bf80f4bSopenharmony_ci } 2958bf80f4bSopenharmony_ci FT_Done_Face(face); 2968bf80f4bSopenharmony_ci } else { 2978bf80f4bSopenharmony_ci CORE_LOG_W("failed to create face: %s", path.data()); 2988bf80f4bSopenharmony_ci } 2998bf80f4bSopenharmony_ci } while (faceIndex < numFaces); 3008bf80f4bSopenharmony_ci} 3018bf80f4bSopenharmony_ci 3028bf80f4bSopenharmony_civoid FontManager::GetTypeFacesByDir(vector<TypeFace>& typeFaces, string_view path) 3038bf80f4bSopenharmony_ci{ 3048bf80f4bSopenharmony_ci auto& fileManager = renderContext_.GetEngine().GetFileManager(); 3058bf80f4bSopenharmony_ci IDirectory::Ptr dir = fileManager.OpenDirectory(path); 3068bf80f4bSopenharmony_ci if (!dir) { 3078bf80f4bSopenharmony_ci return; 3088bf80f4bSopenharmony_ci } 3098bf80f4bSopenharmony_ci 3108bf80f4bSopenharmony_ci vector<IDirectory::Entry> const files = dir->GetEntries(); 3118bf80f4bSopenharmony_ci CORE_LOG_N("check dir '%s' with %zu entries", path.data(), files.size()); 3128bf80f4bSopenharmony_ci 3138bf80f4bSopenharmony_ci for (auto const& file : files) { 3148bf80f4bSopenharmony_ci if (file.type == IDirectory::Entry::Type::FILE) { 3158bf80f4bSopenharmony_ci GetTypeFacesByFile(typeFaces, path + file.name); 3168bf80f4bSopenharmony_ci } 3178bf80f4bSopenharmony_ci } 3188bf80f4bSopenharmony_ci} 3198bf80f4bSopenharmony_ci 3208bf80f4bSopenharmony_ciFT_Face FontManager::OpenFtFace(array_view<const uint8_t> buf, FT_Long index) 3218bf80f4bSopenharmony_ci{ 3228bf80f4bSopenharmony_ci CORE_ASSERT_MSG(fontLib_, "font library is not initialized"); 3238bf80f4bSopenharmony_ci 3248bf80f4bSopenharmony_ci FT_Face face; 3258bf80f4bSopenharmony_ci FT_Error err = FT_New_Memory_Face(fontLib_, buf.data(), (FT_Long)buf.size(), index, &face); 3268bf80f4bSopenharmony_ci if (err) { 3278bf80f4bSopenharmony_ci CORE_LOG_E("failed to init font face"); 3288bf80f4bSopenharmony_ci return nullptr; 3298bf80f4bSopenharmony_ci } 3308bf80f4bSopenharmony_ci if (!face->charmap) { 3318bf80f4bSopenharmony_ci CORE_LOG_E("failed to init font face, no unicode charmap available"); 3328bf80f4bSopenharmony_ci FT_Done_Face(face); 3338bf80f4bSopenharmony_ci return nullptr; 3348bf80f4bSopenharmony_ci } 3358bf80f4bSopenharmony_ci 3368bf80f4bSopenharmony_ci CORE_ASSERT(face->num_glyphs > 0); 3378bf80f4bSopenharmony_ci 3388bf80f4bSopenharmony_ci return face; 3398bf80f4bSopenharmony_ci} 3408bf80f4bSopenharmony_ci 3418bf80f4bSopenharmony_ciFontManager::AtlasTexture* FontManager::CreateAtlasTexture(bool color) 3428bf80f4bSopenharmony_ci{ 3438bf80f4bSopenharmony_ci // Access locked from caller already 3448bf80f4bSopenharmony_ci auto tex = &atlasTextures_.emplace_back(); 3458bf80f4bSopenharmony_ci const ComponentMapping colorSwizzle { CORE_COMPONENT_SWIZZLE_B, CORE_COMPONENT_SWIZZLE_G, CORE_COMPONENT_SWIZZLE_R, 3468bf80f4bSopenharmony_ci CORE_COMPONENT_SWIZZLE_A }; // BGRA swizzle 3478bf80f4bSopenharmony_ci const ComponentMapping monoSwizzle { CORE_COMPONENT_SWIZZLE_R, CORE_COMPONENT_SWIZZLE_R, CORE_COMPONENT_SWIZZLE_R, 3488bf80f4bSopenharmony_ci CORE_COMPONENT_SWIZZLE_R }; // RRRR swizzle 3498bf80f4bSopenharmony_ci const GpuImageDesc desc { 3508bf80f4bSopenharmony_ci ImageType::CORE_IMAGE_TYPE_2D, // imageType 3518bf80f4bSopenharmony_ci ImageViewType::CORE_IMAGE_VIEW_TYPE_2D, // imageViewType 3528bf80f4bSopenharmony_ci color ? Format::BASE_FORMAT_R8G8B8A8_SRGB : Format::BASE_FORMAT_R8_UNORM, // format 3538bf80f4bSopenharmony_ci ImageTiling::CORE_IMAGE_TILING_OPTIMAL, // imageTiling 3548bf80f4bSopenharmony_ci ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSFER_DST_BIT | 3558bf80f4bSopenharmony_ci ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT, // usageFlags 3568bf80f4bSopenharmony_ci MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, // memoryPropertyFlags 3578bf80f4bSopenharmony_ci 0, // ImageCreateFlags 3588bf80f4bSopenharmony_ci EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS, // EngineImageCreationFlags 3598bf80f4bSopenharmony_ci FontDefs::ATLAS_SIZE, // width 3608bf80f4bSopenharmony_ci FontDefs::ATLAS_SIZE, // height 3618bf80f4bSopenharmony_ci 1, // depth 3628bf80f4bSopenharmony_ci 1, // mip count 3638bf80f4bSopenharmony_ci 1, // layer count 3648bf80f4bSopenharmony_ci SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT, // sample count 3658bf80f4bSopenharmony_ci color ? colorSwizzle : monoSwizzle // swizzle 3668bf80f4bSopenharmony_ci }; 3678bf80f4bSopenharmony_ci auto& gpuResourceManager = renderContext_.GetDevice().GetGpuResourceManager(); 3688bf80f4bSopenharmony_ci tex->handle = gpuResourceManager.Create(desc); 3698bf80f4bSopenharmony_ci tex->widthLeft = FontDefs::ATLAS_SIZE; 3708bf80f4bSopenharmony_ci tex->inColor = color; 3718bf80f4bSopenharmony_ci 3728bf80f4bSopenharmony_ci#if defined(FONT_VALIDATION_ENABLED) && (FONT_VALIDATION_ENABLED) 3738bf80f4bSopenharmony_ci string atlasName = "FontAtlas:"; 3748bf80f4bSopenharmony_ci atlasName += to_string(reinterpret_cast<uintptr_t>(this)); 3758bf80f4bSopenharmony_ci atlasName += ':'; 3768bf80f4bSopenharmony_ci atlasName += to_string(atlasTextures_.size()); 3778bf80f4bSopenharmony_ci tex->name = atlasName; 3788bf80f4bSopenharmony_ci CORE_LOG_N("Created atlas '%s' gpuHnd: %llx", tex->name.data(), tex->handle.GetHandle().id); 3798bf80f4bSopenharmony_ci#endif 3808bf80f4bSopenharmony_ci 3818bf80f4bSopenharmony_ci // Clear the atlas as we don't initialize borders when copying glyphs 3828bf80f4bSopenharmony_ci auto staging = static_cast<IRenderDataStoreDefaultStaging*>( 3838bf80f4bSopenharmony_ci renderContext_.GetRenderDataStoreManager().GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_STAGING)); 3848bf80f4bSopenharmony_ci ClearColorValue zero { 0.f, 0.f, 0.f, 0.f }; 3858bf80f4bSopenharmony_ci staging->ClearColorImage(tex->handle, zero); 3868bf80f4bSopenharmony_ci return tex; 3878bf80f4bSopenharmony_ci} 3888bf80f4bSopenharmony_ci 3898bf80f4bSopenharmony_ciint FontManager::UpdateAtlas(FontDefs::Glyph& glyph, const FT_Bitmap& bitmap, bool inColor) 3908bf80f4bSopenharmony_ci{ 3918bf80f4bSopenharmony_ci uint32_t width = bitmap.width + BORDER_WIDTH_X2; 3928bf80f4bSopenharmony_ci uint32_t height = bitmap.rows + BORDER_WIDTH_X2; 3938bf80f4bSopenharmony_ci 3948bf80f4bSopenharmony_ci // Find best fit (but larger) column in atlases 3958bf80f4bSopenharmony_ci uint32_t bestFitAtlas = 0; 3968bf80f4bSopenharmony_ci uint32_t bestFitColumn = 0; 3978bf80f4bSopenharmony_ci uint32_t bestFitColumnPos = 0; 3988bf80f4bSopenharmony_ci uint32_t minDiff = UINT32_MAX; 3998bf80f4bSopenharmony_ci 4008bf80f4bSopenharmony_ci std::lock_guard writerLock(atlasMutex_); 4018bf80f4bSopenharmony_ci 4028bf80f4bSopenharmony_ci for (uint32_t i = 0; i < atlasTextures_.size(); ++i) { 4038bf80f4bSopenharmony_ci auto& atlas = atlasTextures_[i]; 4048bf80f4bSopenharmony_ci if (inColor == atlas.inColor) { 4058bf80f4bSopenharmony_ci uint32_t colPos = 0; 4068bf80f4bSopenharmony_ci for (uint32_t col = 0; col < atlas.columns.size(); ++col) { 4078bf80f4bSopenharmony_ci auto& hdr = atlas.columns[col]; 4088bf80f4bSopenharmony_ci colPos += hdr.colWidth; 4098bf80f4bSopenharmony_ci } 4108bf80f4bSopenharmony_ci } 4118bf80f4bSopenharmony_ci } 4128bf80f4bSopenharmony_ci 4138bf80f4bSopenharmony_ci if (minDiff <= GLYPH_FIT_THRESHOLD) { 4148bf80f4bSopenharmony_ci // Close enough 4158bf80f4bSopenharmony_ci auto& atlas = atlasTextures_[bestFitAtlas]; 4168bf80f4bSopenharmony_ci auto& hdr = atlas.columns[bestFitColumn]; 4178bf80f4bSopenharmony_ci AddGlyphToColumn(glyph, bestFitAtlas, hdr, bitmap, bestFitColumnPos); 4188bf80f4bSopenharmony_ci return ATLAS_OK; 4198bf80f4bSopenharmony_ci } 4208bf80f4bSopenharmony_ci 4218bf80f4bSopenharmony_ci // Need to create new atlas 4228bf80f4bSopenharmony_ci size_t i = atlasTextures_.size(); 4238bf80f4bSopenharmony_ci auto atlas = CreateAtlasTexture(inColor); 4248bf80f4bSopenharmony_ci atlas->widthLeft -= width; 4258bf80f4bSopenharmony_ci auto& hdr = atlas->columns.emplace_back(); 4268bf80f4bSopenharmony_ci hdr.colWidth = static_cast<uint16_t>(width); 4278bf80f4bSopenharmony_ci hdr.heightLeft = static_cast<uint16_t>(ATLAS_SIZE); 4288bf80f4bSopenharmony_ci AddGlyphToColumn(glyph, i, hdr, bitmap, 0); 4298bf80f4bSopenharmony_ci return ATLAS_OK; 4308bf80f4bSopenharmony_ci} 4318bf80f4bSopenharmony_ci 4328bf80f4bSopenharmony_civoid FontManager::UploadPending() 4338bf80f4bSopenharmony_ci{ 4348bf80f4bSopenharmony_ci std::lock_guard writerLock(atlasMutex_); 4358bf80f4bSopenharmony_ci if (std::all_of(atlasTextures_.cbegin(), atlasTextures_.cend(), 4368bf80f4bSopenharmony_ci [](const AtlasTexture& atlas) { return atlas.pending.empty(); })) { 4378bf80f4bSopenharmony_ci return; 4388bf80f4bSopenharmony_ci } 4398bf80f4bSopenharmony_ci 4408bf80f4bSopenharmony_ci struct ColumnSize { 4418bf80f4bSopenharmony_ci uint32_t index; 4428bf80f4bSopenharmony_ci uint32_t count; 4438bf80f4bSopenharmony_ci uint16_t width; 4448bf80f4bSopenharmony_ci uint16_t height; 4458bf80f4bSopenharmony_ci uint32_t byteSize; 4468bf80f4bSopenharmony_ci }; 4478bf80f4bSopenharmony_ci BASE_NS::vector<BASE_NS::vector<ColumnSize>> allColumnWidths; 4488bf80f4bSopenharmony_ci allColumnWidths.reserve(atlasTextures_.size()); 4498bf80f4bSopenharmony_ci uint32_t totalSize = 0U; 4508bf80f4bSopenharmony_ci for (auto& atlas : atlasTextures_) { 4518bf80f4bSopenharmony_ci auto& columnWidths = allColumnWidths.emplace_back(); 4528bf80f4bSopenharmony_ci columnWidths.reserve(atlas.pending.size()); 4538bf80f4bSopenharmony_ci } 4548bf80f4bSopenharmony_ci if (!totalSize) { 4558bf80f4bSopenharmony_ci return; 4568bf80f4bSopenharmony_ci } 4578bf80f4bSopenharmony_ci 4588bf80f4bSopenharmony_ci // create a staging buffer big enough for all the columns 4598bf80f4bSopenharmony_ci const GpuBufferDesc desc { 4608bf80f4bSopenharmony_ci BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT, // usageFlags 4618bf80f4bSopenharmony_ci MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 4628bf80f4bSopenharmony_ci MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT, // memoryPropertyFlags 4638bf80f4bSopenharmony_ci EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE | 4648bf80f4bSopenharmony_ci EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_DEFERRED_DESTROY | 4658bf80f4bSopenharmony_ci EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER, // engineCreationFlags 4668bf80f4bSopenharmony_ci totalSize, // byteSize 4678bf80f4bSopenharmony_ci BASE_NS::Format::BASE_FORMAT_UNDEFINED, // format 4688bf80f4bSopenharmony_ci }; 4698bf80f4bSopenharmony_ci auto& gpuResMan = renderContext_.GetDevice().GetGpuResourceManager(); 4708bf80f4bSopenharmony_ci auto bufferHandle = gpuResMan.Create(desc); 4718bf80f4bSopenharmony_ci auto* ptr = static_cast<uint8_t*>(gpuResMan.MapBufferMemory(bufferHandle)); 4728bf80f4bSopenharmony_ci if (!ptr) { 4738bf80f4bSopenharmony_ci return; 4748bf80f4bSopenharmony_ci } 4758bf80f4bSopenharmony_ci auto buffer = array_view(ptr, totalSize); 4768bf80f4bSopenharmony_ci std::fill(buffer.begin(), buffer.end(), uint8_t(0u)); 4778bf80f4bSopenharmony_ci} 4788bf80f4bSopenharmony_ci 4798bf80f4bSopenharmony_civoid FontManager::AddGlyphToColumn( 4808bf80f4bSopenharmony_ci Glyph& glyph, size_t atlasIndex, ColumnHeader& hdr, const FT_Bitmap& bitmap, uint32_t columnX) 4818bf80f4bSopenharmony_ci{ 4828bf80f4bSopenharmony_ci uint32_t width = bitmap.width; 4838bf80f4bSopenharmony_ci uint32_t height = bitmap.rows; 4848bf80f4bSopenharmony_ci 4858bf80f4bSopenharmony_ci uint32_t x = columnX + BORDER_WIDTH; 4868bf80f4bSopenharmony_ci uint32_t y = ATLAS_SIZE - hdr.heightLeft + BORDER_WIDTH; 4878bf80f4bSopenharmony_ci 4888bf80f4bSopenharmony_ci hdr.heightLeft -= static_cast<uint16_t>(height + BORDER_WIDTH_X2); 4898bf80f4bSopenharmony_ci 4908bf80f4bSopenharmony_ci glyph.atlas.index = static_cast<uint16_t>(atlasIndex); 4918bf80f4bSopenharmony_ci glyph.atlas.rect.x = static_cast<uint16_t>(x); 4928bf80f4bSopenharmony_ci glyph.atlas.rect.y = static_cast<uint16_t>(y); 4938bf80f4bSopenharmony_ci glyph.atlas.rect.w = static_cast<uint16_t>(width); 4948bf80f4bSopenharmony_ci glyph.atlas.rect.h = static_cast<uint16_t>(height); 4958bf80f4bSopenharmony_ci 4968bf80f4bSopenharmony_ci // Access locked by caller 4978bf80f4bSopenharmony_ci uint32_t bpp = (atlasTextures_[atlasIndex].inColor ? 4u : 1u); 4988bf80f4bSopenharmony_ci 4998bf80f4bSopenharmony_ci if (width > 0 && height > 0 && bitmap.pitch / bpp >= width) { 5008bf80f4bSopenharmony_ci atlasTextures_[atlasIndex].pending.push_back({ 5018bf80f4bSopenharmony_ci static_cast<uint16_t>(x), 5028bf80f4bSopenharmony_ci static_cast<uint16_t>(y), 5038bf80f4bSopenharmony_ci static_cast<uint16_t>(width), 5048bf80f4bSopenharmony_ci static_cast<uint16_t>(height), 5058bf80f4bSopenharmony_ci { bitmap.buffer, bitmap.buffer + bitmap.pitch * bitmap.rows }, 5068bf80f4bSopenharmony_ci }); 5078bf80f4bSopenharmony_ci } 5088bf80f4bSopenharmony_ci} 5098bf80f4bSopenharmony_ci 5108bf80f4bSopenharmony_civoid FontManager::Gc(uint64_t uid, FontBuffer* data) 5118bf80f4bSopenharmony_ci{ 5128bf80f4bSopenharmony_ci // Check if file data cache has this font 5138bf80f4bSopenharmony_ci std::lock_guard writerLock(fontBuffersMutex_); 5148bf80f4bSopenharmony_ci 5158bf80f4bSopenharmony_ci if (!fontBuffers_.erase(uid)) { 5168bf80f4bSopenharmony_ci for (auto it = fontBuffers_.cbegin(); it != fontBuffers_.cend();) { 5178bf80f4bSopenharmony_ci if (it->second.expired()) { 5188bf80f4bSopenharmony_ci fontBuffers_.erase(it); 5198bf80f4bSopenharmony_ci } else { 5208bf80f4bSopenharmony_ci ++it; 5218bf80f4bSopenharmony_ci } 5228bf80f4bSopenharmony_ci } 5238bf80f4bSopenharmony_ci } 5248bf80f4bSopenharmony_ci if (fontBuffers_.empty()) { 5258bf80f4bSopenharmony_ci FlushCaches(); 5268bf80f4bSopenharmony_ci } 5278bf80f4bSopenharmony_ci} 5288bf80f4bSopenharmony_ci 5298bf80f4bSopenharmony_ciconst CORE_NS::IInterface* FontManager::GetInterface(const BASE_NS::Uid& uid) const 5308bf80f4bSopenharmony_ci{ 5318bf80f4bSopenharmony_ci if (uid == CORE_NS::IInterface::UID) { 5328bf80f4bSopenharmony_ci return this; 5338bf80f4bSopenharmony_ci } 5348bf80f4bSopenharmony_ci if (uid == IFontManager::UID) { 5358bf80f4bSopenharmony_ci return this; 5368bf80f4bSopenharmony_ci } 5378bf80f4bSopenharmony_ci return nullptr; 5388bf80f4bSopenharmony_ci} 5398bf80f4bSopenharmony_ci 5408bf80f4bSopenharmony_ciCORE_NS::IInterface* FontManager::GetInterface(const BASE_NS::Uid& uid) 5418bf80f4bSopenharmony_ci{ 5428bf80f4bSopenharmony_ci if (uid == CORE_NS::IInterface::UID) { 5438bf80f4bSopenharmony_ci return this; 5448bf80f4bSopenharmony_ci } 5458bf80f4bSopenharmony_ci if (uid == IFontManager::UID) { 5468bf80f4bSopenharmony_ci return this; 5478bf80f4bSopenharmony_ci } 5488bf80f4bSopenharmony_ci return nullptr; 5498bf80f4bSopenharmony_ci} 5508bf80f4bSopenharmony_ci 5518bf80f4bSopenharmony_civoid FontManager::Ref() 5528bf80f4bSopenharmony_ci{ 5538bf80f4bSopenharmony_ci refcnt_.fetch_add(1, std::memory_order_relaxed); 5548bf80f4bSopenharmony_ci} 5558bf80f4bSopenharmony_ci 5568bf80f4bSopenharmony_civoid FontManager::Unref() 5578bf80f4bSopenharmony_ci{ 5588bf80f4bSopenharmony_ci if (refcnt_.fetch_sub(1, std::memory_order_release) == 1) { 5598bf80f4bSopenharmony_ci std::atomic_thread_fence(std::memory_order_acquire); 5608bf80f4bSopenharmony_ci CORE_LOG_N("delete FontManager %p", this); 5618bf80f4bSopenharmony_ci delete this; 5628bf80f4bSopenharmony_ci } 5638bf80f4bSopenharmony_ci} 5648bf80f4bSopenharmony_ciFONT_END_NAMESPACE() 565