1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <charconv>
17 #include <dlfcn.h>
18 #ifdef USE_M133_SKIA
19 #include <unistd.h>
20 #endif
21
22 #include "astc_codec.h"
23 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
24 #include "image_compressor.h"
25 #endif
26 #include "image_log.h"
27 #include "image_trace.h"
28 #include "image_system_properties.h"
29 #include "image_trace.h"
30 #include "securec.h"
31 #include "media_errors.h"
32 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
33 #include "v1_0/buffer_handle_meta_key_type.h"
34 #include "vpe_utils.h"
35 #endif
36
37 #undef LOG_DOMAIN
38 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
39
40 #undef LOG_TAG
41 #define LOG_TAG "AstcCodec"
42
43 namespace OHOS {
44 namespace ImagePlugin {
45 using namespace Media;
46 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
47 using namespace OHOS::HDI::Display::Graphic::Common::V1_0;
48 #endif
49 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
50 using namespace AstcEncBasedCl;
51 #endif
52 constexpr uint8_t TEXTURE_HEAD_BYTES = 16;
53 constexpr uint8_t ASTC_MASK = 0xFF;
54 constexpr uint8_t ASTC_NUM_4 = 4; // represents ASTC_EXTEND_INFO_SIZE_DEFINITION_LENGTH
55 constexpr uint8_t ASTC_NUM_8 = 8;
56 constexpr uint8_t ASTC_HEADER_SIZE = 16;
57 constexpr uint8_t ASTC_NUM_24 = 24;
58 static const uint32_t ASTC_MAGIC_ID = 0x5CA1AB13;
59 constexpr uint8_t DEFAULT_DIM = 4;
60 constexpr uint8_t MAX_DIM = 12;
61 constexpr uint8_t HIGH_SPEED_PROFILE_MAP_QUALITY = 20; // quality level is 20 for thumbnail
62 constexpr uint8_t RGBA_BYTES_PIXEL_LOG2 = 2;
63 constexpr uint8_t MASKBITS_FOR_8BITS = 255;
64 constexpr uint8_t UINT32_1TH_BYTES = 8;
65 constexpr uint8_t UINT32_2TH_BYTES = 16;
66 constexpr uint8_t UINT32_3TH_BYTES = 24;
67 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
68 constexpr int32_t WIDTH_CL_THRESHOLD = 256;
69 constexpr int32_t HEIGHT_CL_THRESHOLD = 256;
70 #endif
71 constexpr int32_t WIDTH_MAX_ASTC = 8192;
72 constexpr int32_t HEIGHT_MAX_ASTC = 8192;
73
74 #ifdef SUT_ENCODE_ENABLE
CheckClBinIsExist(const std::string & name)75 static bool CheckClBinIsExist(const std::string &name)
76 {
77 return (access(name.c_str(), F_OK) != -1); // -1 means that the file is not exist
78 }
79 #endif
80 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
CheckClBinIsExistWithLock(const std::string & name)81 static bool CheckClBinIsExistWithLock(const std::string &name)
82 {
83 std::lock_guard<std::mutex> lock(checkClBinPathMutex);
84 return (access(name.c_str(), F_OK) != -1); // -1 means that the file is not exist
85 }
86 #endif
87
88 struct AstcEncCheckInfo {
89 uint32_t pixmapInSize = 0;
90 uint32_t astcBufferSize = 0;
91 uint32_t extendInfoSize = 0;
92 uint32_t extendBufferSize = 0;
93 PixelFormat pixmapFormat = PixelFormat::UNKNOWN;
94 };
95
96 #ifdef SUT_ENCODE_ENABLE
97 constexpr uint8_t EXPAND_ASTC_INFO_MAX_ENC = 16;
98 constexpr int32_t EXPAND_SIZE_BYTES_ENC = 4;
99
100 struct AstcInInfo {
101 const uint8_t* astcBuf;
102 int32_t astcBytes;
103 uint8_t expandNums;
104 uint8_t expandInfoType[EXPAND_ASTC_INFO_MAX_ENC];
105 int32_t expandInfoBytes[EXPAND_ASTC_INFO_MAX_ENC];
106 uint8_t* expandInfoBuf[EXPAND_ASTC_INFO_MAX_ENC];
107 };
108 struct SutOutInfo {
109 uint8_t* sutBuf;
110 int32_t sutCapacity;
111 int32_t sutBytes;
112 };
113 #ifdef SUT_PATH_X64
114 static const std::string g_textureSuperEncSo = "/system/lib64/module/hms/graphic/libtextureSuperCompress.z.so";
115 #else
116 static const std::string g_textureSuperEncSo = "/system/lib/module/hms/graphic/libtextureSuperCompress.z.so";
117 #endif
118 using SuperCompressTexture = bool (*)(const AstcInInfo&, SutOutInfo&, uint32_t);
119 class SutEncSoManager {
120 public:
121 SutEncSoManager();
122 ~SutEncSoManager();
123 bool LoadSutEncSo();
124 SuperCompressTexture sutEncSoEncFunc_;
125 private:
126 bool sutEncSoOpened_;
127 void *textureEncSoHandle_;
128 std::mutex sutEncSoMutex_ = {};
129 };
130
131 static SutEncSoManager g_sutEncSoManager;
132
SutEncSoManager()133 SutEncSoManager::SutEncSoManager()
134 {
135 sutEncSoOpened_ = false;
136 textureEncSoHandle_ = nullptr;
137 sutEncSoEncFunc_ = nullptr;
138 }
139
~SutEncSoManager()140 SutEncSoManager::~SutEncSoManager()
141 {
142 bool sutEncHasBeenOpen = sutEncSoOpened_ && (textureEncSoHandle_ != nullptr);
143 if (sutEncHasBeenOpen) {
144 int ret = dlclose(textureEncSoHandle_);
145 IMAGE_LOGD("astcenc dlcose ret: %{public}d %{public}s!", ret, g_textureSuperEncSo.c_str());
146 }
147 }
148
LoadSutEncSo()149 bool SutEncSoManager::LoadSutEncSo()
150 {
151 std::lock_guard<std::mutex> lock(sutEncSoMutex_);
152 if (!sutEncSoOpened_) {
153 if (!CheckClBinIsExist(g_textureSuperEncSo)) {
154 IMAGE_LOGE("sut %{public}s! is not found", g_textureSuperEncSo.c_str());
155 return false;
156 }
157 textureEncSoHandle_ = dlopen(g_textureSuperEncSo.c_str(), 1);
158 if (textureEncSoHandle_ == nullptr) {
159 IMAGE_LOGE("sut libtextureSuperCompress dlopen failed!");
160 return false;
161 }
162 sutEncSoEncFunc_ =
163 reinterpret_cast<SuperCompressTexture>(dlsym(textureEncSoHandle_, "SuperCompressTextureTlv"));
164 if (sutEncSoEncFunc_ == nullptr) {
165 IMAGE_LOGE("sut libtextureSuperCompress dlsym failed!");
166 dlclose(textureEncSoHandle_);
167 textureEncSoHandle_ = nullptr;
168 return false;
169 }
170 IMAGE_LOGD("astcenc dlopen success: %{public}s!", g_textureSuperEncSo.c_str());
171 sutEncSoOpened_ = true;
172 }
173 return true;
174 }
175 #endif
176
SetAstcEncode(OutputDataStream * outputStream,PlEncodeOptions & option,Media::PixelMap * pixelMap)177 uint32_t AstcCodec::SetAstcEncode(OutputDataStream* outputStream, PlEncodeOptions &option, Media::PixelMap* pixelMap)
178 {
179 if (outputStream == nullptr || pixelMap == nullptr) {
180 IMAGE_LOGE("input data is nullptr.");
181 return ERROR;
182 }
183 astcOutput_ = outputStream;
184 astcOpts_ = option;
185 astcPixelMap_ = pixelMap;
186 return SUCCESS;
187 }
188
189 // test ASTCEncoder
GenAstcHeader(uint8_t * header,astcenc_image img,TextureEncodeOptions & encodeParams)190 uint32_t GenAstcHeader(uint8_t *header, astcenc_image img, TextureEncodeOptions &encodeParams)
191 {
192 uint8_t *tmp = header;
193 *tmp++ = ASTC_MAGIC_ID & ASTC_MASK;
194 *tmp++ = (ASTC_MAGIC_ID >> ASTC_NUM_8) & ASTC_MASK;
195 *tmp++ = (ASTC_MAGIC_ID >> ASTC_HEADER_SIZE) & ASTC_MASK;
196 *tmp++ = (ASTC_MAGIC_ID >> ASTC_NUM_24) & ASTC_MASK;
197 *tmp++ = static_cast<uint8_t>(encodeParams.blockX_);
198 *tmp++ = static_cast<uint8_t>(encodeParams.blockY_);
199 *tmp++ = 1;
200 *tmp++ = img.dim_x & ASTC_MASK;
201 *tmp++ = (img.dim_x >> ASTC_NUM_8) & ASTC_MASK;
202 *tmp++ = (img.dim_x >> ASTC_HEADER_SIZE) & ASTC_MASK;
203 *tmp++ = img.dim_y & ASTC_MASK;
204 *tmp++ = (img.dim_y >> ASTC_NUM_8) & ASTC_MASK;
205 *tmp++ = (img.dim_y >> ASTC_HEADER_SIZE) & ASTC_MASK;
206 *tmp++ = img.dim_z & ASTC_MASK;
207 *tmp++ = (img.dim_z >> ASTC_NUM_8) & ASTC_MASK;
208 *tmp++ = (img.dim_z >> ASTC_HEADER_SIZE) & ASTC_MASK;
209 return SUCCESS;
210 }
211
InitAstcencConfig(AstcEncoder * work,TextureEncodeOptions * option)212 uint32_t InitAstcencConfig(AstcEncoder* work, TextureEncodeOptions* option)
213 {
214 bool invaildInput = (work == nullptr) || (option == nullptr);
215 if (invaildInput) {
216 IMAGE_LOGE("astc input work or option is nullptr.");
217 return ERROR;
218 }
219 unsigned int blockX = option->blockX_;
220 unsigned int blockY = option->blockY_;
221 unsigned int blockZ = 1;
222
223 float quality = ASTCENC_PRE_FAST;
224 unsigned int flags = ASTCENC_FLG_SELF_DECOMPRESS_ONLY;
225 astcenc_error status = astcenc_config_init(work->profile, blockX, blockY,
226 blockZ, quality, flags, &work->config);
227 if (status != ASTCENC_SUCCESS) {
228 IMAGE_LOGE("ERROR: astcenc_config_init failed, status %{public}d", status);
229 return ERROR;
230 }
231 work->config.privateProfile = option->privateProfile_;
232 if (work->config.privateProfile == HIGH_SPEED_PROFILE) {
233 work->config.tune_refinement_limit = 1;
234 work->config.tune_candidate_limit = 1;
235 work->config.tune_partition_count_limit = 1;
236 }
237 if (astcenc_context_alloc(&work->config, 1, &work->codec_context) != ASTCENC_SUCCESS) {
238 return ERROR;
239 }
240 return SUCCESS;
241 }
242
extractDimensions(std::string & format,TextureEncodeOptions & param)243 void extractDimensions(std::string &format, TextureEncodeOptions ¶m)
244 {
245 param.blockX_ = DEFAULT_DIM;
246 param.blockY_ = DEFAULT_DIM;
247 std::size_t slashPos = format.rfind('/');
248 if (slashPos != std::string::npos) {
249 std::string dimensions = format.substr(slashPos + 1);
250 std::size_t starPos = dimensions.find('*');
251 if (starPos != std::string::npos) {
252 std::string widthStr = dimensions.substr(0, starPos);
253 std::string heightStr = dimensions.substr(starPos + 1);
254
255 auto ret_x = std::from_chars(widthStr.data(), widthStr.data() + widthStr.size(), param.blockX_);
256 auto ret_y = std::from_chars(heightStr.data(), heightStr.data() + heightStr.size(), param.blockY_);
257 if (!(ret_x.ec == std::errc() && ret_y.ec == std::errc())) {
258 IMAGE_LOGE("Failed to convert string to number");
259 }
260 }
261 }
262 }
263
264 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
265 constexpr double MAX_PSNR = 99.9;
266 constexpr double MAX_VALUE = 255;
267 constexpr double THRESHOLD_R = 30.0;
268 constexpr double THRESHOLD_G = 30.0;
269 constexpr double THRESHOLD_B = 30.0;
270 constexpr double THRESHOLD_A = 30.0;
271 constexpr double THRESHOLD_RGB = 30.0;
272 constexpr double LOG_BASE = 10.0;
CheckQuality(int32_t * mseIn[RGBA_COM],int blockNum,int blockXYZ)273 bool CheckQuality(int32_t *mseIn[RGBA_COM], int blockNum, int blockXYZ)
274 {
275 double psnr[RGBA_COM + 1];
276 const double threshold[RGBA_COM + 1] = {THRESHOLD_R, THRESHOLD_G, THRESHOLD_B, THRESHOLD_A, THRESHOLD_RGB};
277 uint64_t mseTotal[RGBA_COM + 1] = {0, 0, 0, 0, 0};
278 for (int i = R_COM; i < RGBA_COM; i++) {
279 int32_t *mse = mseIn[i];
280 if (!mse) {
281 return false;
282 }
283 for (int j = 0; j < blockNum; j++) {
284 mseTotal[i] += *mse;
285 if (i != A_COM) mseTotal[RGBA_COM] += *mse;
286 mse++;
287 }
288 }
289 for (int i = R_COM; i < RGBA_COM; i++) {
290 if (mseTotal[i] == 0) {
291 psnr[i] = MAX_PSNR;
292 continue;
293 }
294 double mseRgb = static_cast<double>(mseTotal[i] / static_cast<uint64_t>((blockNum * blockXYZ)));
295 psnr[i] = LOG_BASE * log(static_cast<double>(MAX_VALUE * MAX_VALUE) / mseRgb) / log(LOG_BASE);
296 }
297 if (mseTotal[RGBA_COM] == 0) {
298 psnr[RGBA_COM] = MAX_PSNR;
299 } else {
300 double mseRgb = static_cast<double>(
301 mseTotal[RGBA_COM] / static_cast<uint64_t>((blockNum * blockXYZ * (RGBA_COM - 1))));
302 psnr[RGBA_COM] = LOG_BASE * log(static_cast<double>(MAX_VALUE * MAX_VALUE) / mseRgb) / log(LOG_BASE);
303 }
304 IMAGE_LOGD("astc psnr r%{public}f g%{public}f b%{public}f a%{public}f rgb%{public}f",
305 psnr[R_COM], psnr[G_COM], psnr[B_COM], psnr[A_COM],
306 psnr[RGBA_COM]);
307 return (psnr[R_COM] > threshold[R_COM]) && (psnr[G_COM] > threshold[G_COM])
308 && (psnr[B_COM] > threshold[B_COM]) && (psnr[A_COM] > threshold[A_COM])
309 && (psnr[RGBA_COM] > threshold[RGBA_COM]);
310 }
311 #endif
312
FreeMem(AstcEncoder * work)313 static void FreeMem(AstcEncoder *work)
314 {
315 if (!work) {
316 return;
317 }
318 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
319 if (work->calQualityEnable) {
320 for (int i = R_COM; i < RGBA_COM; i++) {
321 if (work->mse[i]) {
322 free(work->mse[i]);
323 work->mse[i] = nullptr;
324 }
325 }
326 }
327 #endif
328 if (work->image_.data) {
329 free(work->image_.data);
330 work->image_.data = nullptr;
331 }
332 if (work->codec_context != nullptr) {
333 astcenc_context_free(work->codec_context);
334 work->codec_context = nullptr;
335 }
336 work->data_out_ = nullptr;
337 }
338
InitMem(AstcEncoder * work,TextureEncodeOptions param)339 static bool InitMem(AstcEncoder *work, TextureEncodeOptions param)
340 {
341 if (!work) {
342 return false;
343 }
344 work->swizzle_ = {ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A};
345 work->image_.dim_x = static_cast<unsigned int>(param.width_);
346 work->image_.dim_y = static_cast<unsigned int>(param.height_);
347 work->image_.dim_z = 1;
348 if (param.privateProfile_ == HIGH_SPEED_PROFILE_HIGHBITS) {
349 work->image_.data_type = ASTCENC_TYPE_RGBA1010102;
350 } else {
351 work->image_.data_type = ASTCENC_TYPE_U8;
352 }
353 work->image_.dim_stride = static_cast<unsigned int>(param.stride_);
354 work->codec_context = nullptr;
355 work->image_.data = nullptr;
356 work->profile = ASTCENC_PRF_LDR_SRGB;
357 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
358 work->mse[R_COM] = work->mse[G_COM] = work->mse[B_COM] = work->mse[A_COM] = nullptr;
359 work->calQualityEnable = param.enableQualityCheck;
360 if (param.blocksNum <= 0) {
361 IMAGE_LOGE("[AstcCodec] InitMem blocksNum is invalid");
362 return false;
363 }
364 if (work->calQualityEnable) {
365 for (int i = R_COM; i < RGBA_COM; i++) {
366 work->mse[i] = static_cast<int32_t *>(calloc(param.blocksNum, sizeof(int32_t)));
367 if (!work->mse[i]) {
368 IMAGE_LOGE("quality control calloc failed");
369 return false;
370 }
371 }
372 }
373 #endif
374 work->image_.data = static_cast<void **>(malloc(sizeof(void*) * work->image_.dim_z));
375 if (!work->image_.data) {
376 return false;
377 }
378 return true;
379 }
380
AstcSoftwareEncodeCore(TextureEncodeOptions & param,uint8_t * pixmapIn,uint8_t * astcBuffer)381 bool AstcCodec::AstcSoftwareEncodeCore(TextureEncodeOptions ¶m, uint8_t *pixmapIn, uint8_t *astcBuffer)
382 {
383 if ((pixmapIn == nullptr) || (astcBuffer == nullptr)) {
384 IMAGE_LOGE("pixmapIn or astcBuffer is nullptr");
385 return false;
386 }
387 AstcEncoder work;
388 if (!InitMem(&work, param)) {
389 FreeMem(&work);
390 return false;
391 }
392 if (InitAstcencConfig(&work, ¶m) != SUCCESS) {
393 IMAGE_LOGE("astc InitAstcencConfig failed");
394 FreeMem(&work);
395 return false;
396 }
397 work.image_.data[0] = pixmapIn;
398 work.data_out_ = astcBuffer;
399 if (GenAstcHeader(work.data_out_, work.image_, param) != SUCCESS) {
400 IMAGE_LOGE("astc GenAstcHeader failed");
401 FreeMem(&work);
402 return false;
403 }
404 work.error_ = astcenc_compress_image(work.codec_context, &work.image_, &work.swizzle_,
405 work.data_out_ + TEXTURE_HEAD_BYTES, param.astcBytes - TEXTURE_HEAD_BYTES,
406 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
407 work.calQualityEnable, work.mse,
408 #endif
409 0);
410 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
411 if ((ASTCENC_SUCCESS != work.error_) ||
412 (work.calQualityEnable && !CheckQuality(work.mse, param.blocksNum, param.blockX_ * param.blockY_))) {
413 #else
414 if (ASTCENC_SUCCESS != work.error_) {
415 #endif
416 IMAGE_LOGE("astc compress failed");
417 FreeMem(&work);
418 return false;
419 }
420 FreeMem(&work);
421 return true;
422 }
423
424 static QualityProfile GetAstcQuality(int32_t quality)
425 {
426 QualityProfile privateProfile;
427 switch (quality) {
428 case HIGH_SPEED_PROFILE_MAP_QUALITY:
429 privateProfile = HIGH_SPEED_PROFILE;
430 break;
431 default:
432 privateProfile = HIGH_QUALITY_PROFILE;
433 break;
434 }
435 return privateProfile;
436 }
437
438 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
439 bool AstcCodec::TryAstcEncBasedOnCl(TextureEncodeOptions ¶m, uint8_t *inData,
440 uint8_t *buffer, const std::string &clBinPath)
441 {
442 ClAstcHandle *astcClEncoder = nullptr;
443 bool invalidPara = (inData == nullptr) || (buffer == nullptr);
444 if (invalidPara) {
445 IMAGE_LOGE("astc Please check TryAstcEncBasedOnCl input!");
446 return false;
447 }
448 if (AstcClCreate(&astcClEncoder, clBinPath) != CL_ASTC_ENC_SUCCESS) {
449 IMAGE_LOGE("astc AstcClCreate failed!");
450 return false;
451 }
452 ClAstcImageOption imageIn;
453 if (AstcClFillImage(&imageIn, inData, param.stride_, param.width_, param.height_) != CL_ASTC_ENC_SUCCESS) {
454 IMAGE_LOGE("astc AstcClFillImage failed!");
455 AstcClClose(astcClEncoder);
456 return false;
457 }
458 if (AstcClEncImage(astcClEncoder, &imageIn, buffer) != CL_ASTC_ENC_SUCCESS) {
459 IMAGE_LOGE("astc AstcClEncImage failed!");
460 AstcClClose(astcClEncoder);
461 return false;
462 }
463 if (AstcClClose(astcClEncoder) != CL_ASTC_ENC_SUCCESS) {
464 IMAGE_LOGE("astc AstcClClose failed!");
465 return false;
466 }
467 return true;
468 }
469 #endif
470
471 #ifdef SUT_ENCODE_ENABLE
472 static bool FillAstcSutInfo(AstcInInfo &astcInfo, SutOutInfo &sutInfo, TextureEncodeOptions ¶m,
473 uint8_t *astcBuffer)
474 {
475 astcInfo.astcBuf = astcBuffer;
476 astcInfo.astcBytes = param.astcBytes;
477 astcInfo.expandNums = param.expandNums;
478 int32_t expandTotalBytes = 0;
479 for (uint8_t idx = 0; idx < astcInfo.expandNums; idx++) {
480 astcInfo.expandInfoType[idx] = idx;
481 astcInfo.expandInfoBytes[idx] = param.extInfoBytes;
482 astcInfo.expandInfoBuf[idx] = param.extInfoBuf;
483 expandTotalBytes += sizeof(uint8_t) + sizeof(int32_t) + param.extInfoBytes;
484 }
485 sutInfo.sutCapacity = astcInfo.astcBytes + EXPAND_SIZE_BYTES_ENC + expandTotalBytes;
486 sutInfo.sutBuf = static_cast<uint8_t *>(malloc(sutInfo.sutCapacity));
487 if (sutInfo.sutBuf == nullptr) {
488 IMAGE_LOGD("astcenc sutInfo.sutBuf malloc failed!");
489 return false;
490 }
491 return true;
492 }
493
494 static bool SutEncode(TextureEncodeOptions ¶m, uint8_t *astcBuffer)
495 {
496 bool invalidSutEnc = !g_sutEncSoManager.LoadSutEncSo() || g_sutEncSoManager.sutEncSoEncFunc_ == nullptr;
497 if (invalidSutEnc) {
498 IMAGE_LOGE("sut enc so dlopen failed or sutEncSoEncFunc_ is nullptr!");
499 param.sutProfile = SutProfile::SKIP_SUT;
500 return true;
501 }
502 AstcInInfo astcInfo = {0};
503 SutOutInfo sutInfo = {0};
504 int32_t ret = memset_s(&astcInfo, sizeof(AstcInInfo), 0, sizeof(AstcInInfo));
505 if (ret != 0) {
506 IMAGE_LOGE("AstcInInfo memset failed!");
507 return false;
508 }
509 ret = memset_s(&sutInfo, sizeof(SutOutInfo), 0, sizeof(SutOutInfo));
510 if (ret != 0) {
511 IMAGE_LOGE("SutOutInfo memset failed!");
512 return false;
513 }
514
515 if (!FillAstcSutInfo(astcInfo, sutInfo, param, astcBuffer)) {
516 IMAGE_LOGE("FillAstcSutInfo fail");
517 return false;
518 }
519 if (!g_sutEncSoManager.sutEncSoEncFunc_(astcInfo, sutInfo,
520 static_cast<uint32_t>(param.sutProfile))) {
521 IMAGE_LOGE("astc g_sutEncSoEncFunc failed!");
522 free(sutInfo.sutBuf);
523 return false;
524 }
525 if (memcpy_s(astcBuffer, param.astcBytes, sutInfo.sutBuf, sutInfo.sutBytes) < 0) {
526 IMAGE_LOGE("sut sutbuffer is failed to be copied to astcBuffer!");
527 free(sutInfo.sutBuf);
528 return false;
529 }
530 free(sutInfo.sutBuf);
531 param.outIsSut = true;
532 param.astcBytes = sutInfo.sutBytes;
533 param.sutBytes = param.astcBytes;
534 return true;
535 }
536
537 bool AstcCodec::TryTextureSuperCompress(TextureEncodeOptions ¶m, uint8_t *astcBuffer)
538 {
539 bool skipSutEnc = (param.sutProfile == SutProfile::SKIP_SUT) ||
540 ((!param.hardwareFlag) && (param.privateProfile_ != HIGH_SPEED_PROFILE)) ||
541 (param.blockX_ != DEFAULT_DIM && param.blockY_ != DEFAULT_DIM);
542 switch (param.textureEncodeType) {
543 case TextureEncodeType::HDR_ASTC_4X4:
544 case TextureEncodeType::SDR_ASTC_4X4:
545 param.sutProfile = SutProfile::SKIP_SUT;
546 IMAGE_LOGD("sdr_astc_4x4 is not suit to be compressed to sut!");
547 return true;
548 case TextureEncodeType::ASTC:
549 if (skipSutEnc) {
550 IMAGE_LOGD("astc is not suit to be compressed to sut!");
551 param.sutProfile = SutProfile::SKIP_SUT;
552 return true;
553 }
554 break;
555 case TextureEncodeType::SDR_SUT_SUPERFAST_4X4:
556 break;
557 default:
558 IMAGE_LOGE("TextureEncodeType is failed");
559 return false;
560 }
561
562 return SutEncode(param, astcBuffer);
563 }
564 #endif
565
566 static bool GetSutSdrProfile(PlEncodeOptions &astcOpts,
567 SutProfile &sutProfile, QualityProfile &privateProfile)
568 {
569 auto sutNode = SUT_FORMAT_MAP.find(astcOpts.format);
570 if (sutNode != SUT_FORMAT_MAP.end()) {
571 auto [sutQ, sutP, astcP] = sutNode->second;
572 if (sutQ != astcOpts.quality) {
573 IMAGE_LOGE("GetSutSdrProfile failed %{public}d is invalid!", astcOpts.quality);
574 return false;
575 }
576 sutProfile = sutP;
577 privateProfile = astcP;
578 return true;
579 }
580 return false;
581 }
582
583 static bool GetAstcProfile(PlEncodeOptions &astcOpts, QualityProfile &privateProfile)
584 {
585 auto astcNode = ASTC_FORMAT_MAP.find(astcOpts.format);
586 if (astcNode != ASTC_FORMAT_MAP.end()) {
587 const auto &qualityMap = astcNode->second;
588 auto qualityNode = qualityMap.find(astcOpts.quality);
589 if (qualityNode != qualityMap.end()) {
590 privateProfile = qualityNode->second;
591 return true;
592 }
593 IMAGE_LOGE("GetAstcProfile failed %{public}d is invalid!", astcOpts.quality);
594 return false;
595 }
596 return false;
597 }
598
599 bool CheckParamBlockSize(TextureEncodeOptions ¶m)
600 {
601 if ((param.width_ <= 0) || (param.height_ <= 0)) {
602 IMAGE_LOGE("CheckAstcEncInput width <= 0 or height <= 0 !");
603 return false;
604 }
605 if ((param.width_ > WIDTH_MAX_ASTC) || (param.height_ > HEIGHT_MAX_ASTC)) {
606 IMAGE_LOGE("CheckAstcEncInput width %{public}d height %{public}d out of range %{public}d x %{public}d!",
607 param.width_, param.height_, WIDTH_MAX_ASTC, HEIGHT_MAX_ASTC);
608 return false;
609 }
610 if ((param.blockX_ < DEFAULT_DIM) || (param.blockY_ < DEFAULT_DIM)) {
611 IMAGE_LOGE("CheckAstcEncInput block %{public}d x %{public}d < 4 x 4!", param.blockX_, param.blockY_);
612 return false;
613 }
614 if ((param.blockX_ > MAX_DIM) || (param.blockY_ > MAX_DIM)) {
615 IMAGE_LOGE("CheckAstcEncInput block %{public}d x %{public}d > 12 x 12!", param.blockX_, param.blockY_);
616 return false;
617 }
618 return true;
619 }
620
621 static bool InitAstcEncPara(TextureEncodeOptions ¶m,
622 int32_t width, int32_t height, int32_t stride, PlEncodeOptions &astcOpts)
623 {
624 SutProfile sutProfile;
625 QualityProfile qualityProfile;
626 if (astcOpts.format == "image/sdr_sut_superfast_4x4") { // sut sdr encode
627 if (!GetSutSdrProfile(astcOpts, sutProfile, qualityProfile)) {
628 IMAGE_LOGE("InitAstcEncPara GetSutSdrProfile failed");
629 return false;
630 }
631 param.textureEncodeType = TextureEncodeType::SDR_SUT_SUPERFAST_4X4;
632 } else if (astcOpts.format == "image/sdr_astc_4x4") { // astc sdr encode
633 if (!GetAstcProfile(astcOpts, qualityProfile)) {
634 IMAGE_LOGE("InitAstcEncPara GetAstcProfile failed");
635 return false;
636 }
637 sutProfile = SutProfile::SKIP_SUT;
638 param.textureEncodeType = TextureEncodeType::SDR_ASTC_4X4;
639 } else if (astcOpts.format == "image/hdr_astc_4x4") { // astc hdr encode
640 if (!GetAstcProfile(astcOpts, qualityProfile)) {
641 IMAGE_LOGE("InitAstcEncPara GetAstcProfile failed");
642 return false;
643 }
644 sutProfile = SutProfile::SKIP_SUT;
645 param.textureEncodeType = TextureEncodeType::HDR_ASTC_4X4;
646 } else if (astcOpts.format.find("image/astc") == 0) { // old astc encode
647 qualityProfile = GetAstcQuality(astcOpts.quality);
648 sutProfile = SutProfile::SKIP_SUT;
649 param.textureEncodeType = TextureEncodeType::ASTC;
650 } else {
651 IMAGE_LOGE("InitAstcEncPara format invalidation:%{public}s", astcOpts.format.c_str());
652 return false;
653 }
654 param.enableQualityCheck = false;
655 param.hardwareFlag = false;
656 param.sutProfile = sutProfile;
657 param.width_ = width;
658 param.height_ = height;
659 param.stride_ = stride;
660 param.privateProfile_ = qualityProfile;
661 param.outIsSut = false;
662 extractDimensions(astcOpts.format, param);
663 if (!CheckParamBlockSize(param)) { // DEFAULT_DIM = 4
664 IMAGE_LOGE("InitAstcEncPara failed %{public}dx%{public}d is invalid!", param.blockX_, param.blockY_);
665 return false;
666 }
667 param.blocksNum = ((param.width_ + param.blockX_ - 1) / param.blockX_) *
668 ((param.height_ + param.blockY_ - 1) / param.blockY_);
669 param.astcBytes = param.blocksNum * TEXTURE_HEAD_BYTES + TEXTURE_HEAD_BYTES;
670 return true;
671 }
672
673 static void FillAstcEncCheckInfo(AstcEncCheckInfo &checkInfo, Media::PixelMap* astcPixelMap, uint32_t astcBufferSize,
674 uint32_t extendInfoSize, uint32_t extendBufferSize)
675 {
676 checkInfo.pixmapInSize = astcPixelMap->GetAllocationByteCount();
677 checkInfo.pixmapFormat = astcPixelMap->GetPixelFormat();
678 checkInfo.astcBufferSize = astcBufferSize;
679 checkInfo.extendInfoSize = extendInfoSize;
680 checkInfo.extendBufferSize = extendBufferSize;
681 }
682
683 static bool CheckAstcEncInput(TextureEncodeOptions ¶m, AstcEncCheckInfo checkInfo)
684 {
685 uint32_t pixmapStride = static_cast<uint32_t>(param.stride_) << RGBA_BYTES_PIXEL_LOG2;
686 if ((param.width_ <= 0) || (param.height_ <= 0) || (param.stride_ < param.width_)) {
687 IMAGE_LOGE("CheckAstcEncInput width <= 0 or height <= 0 or stride < width!");
688 return false;
689 }
690 if ((param.width_ > WIDTH_MAX_ASTC) || (param.height_ > HEIGHT_MAX_ASTC)) {
691 IMAGE_LOGE("CheckAstcEncInput width %{public}d height %{public}d out of range %{public}d x %{public}d!",
692 param.width_, param.height_, WIDTH_MAX_ASTC, HEIGHT_MAX_ASTC);
693 return false;
694 }
695 uint64_t allocByteCount = static_cast<uint32_t>(param.height_) * pixmapStride;
696 if (allocByteCount > std::numeric_limits<uint32_t>::max()) {
697 IMAGE_LOGE("CheckAstcEncInput height %{public}d stride %{public}d overflow!",
698 param.height_, pixmapStride);
699 return false;
700 }
701 if (checkInfo.pixmapInSize < static_cast<uint32_t>(allocByteCount)) {
702 IMAGE_LOGE("CheckAstcEncInput pixmapInSize %{public}d not enough for height %{public}d stride %{public}d!",
703 checkInfo.pixmapInSize, param.height_, pixmapStride);
704 return false;
705 }
706 if ((param.blockX_ < DEFAULT_DIM) || (param.blockY_ < DEFAULT_DIM)) {
707 IMAGE_LOGE("CheckAstcEncInput block %{public}d x %{public}d < 4 x 4!", param.blockX_, param.blockY_);
708 return false;
709 }
710 if ((param.blockX_ > MAX_DIM) || (param.blockY_ > MAX_DIM)) {
711 IMAGE_LOGE("CheckAstcEncInput block %{public}d x %{public}d > 12 x 12!", param.blockX_, param.blockY_);
712 return false;
713 }
714 const bool isAstcHdr = (param.textureEncodeType == TextureEncodeType::HDR_ASTC_4X4);
715 const PixelFormat expectedFormat = isAstcHdr ? PixelFormat::RGBA_1010102 : PixelFormat::RGBA_8888;
716 if (checkInfo.pixmapFormat != expectedFormat) {
717 IMAGE_LOGE("CheckAstcEncInput textureEncodeType: %{public}d, pixelFormat %{public}d must be RGBA!",
718 param.textureEncodeType, checkInfo.pixmapFormat);
719 return false;
720 }
721 uint32_t packSize = static_cast<uint32_t>(param.astcBytes) + checkInfo.extendInfoSize + checkInfo.extendBufferSize;
722 if (checkInfo.astcBufferSize < packSize) {
723 IMAGE_LOGE("CheckAstcEncInput astcBufferSize %{public}d not enough for %{public}d!",
724 checkInfo.astcBufferSize, packSize);
725 return false;
726 }
727 return true;
728 }
729
730 uint32_t AstcCodec::AstcSoftwareEncode(TextureEncodeOptions ¶m, bool enableQualityCheck,
731 int32_t blocksNum, uint8_t *outBuffer, int32_t outSize)
732 {
733 ImageInfo imageInfo;
734 astcPixelMap_->GetImageInfo(imageInfo);
735 uint8_t *pixmapIn = static_cast<uint8_t *>(astcPixelMap_->GetWritablePixels());
736 uint32_t stride = static_cast<uint32_t>(astcPixelMap_->GetRowStride()) >> RGBA_BYTES_PIXEL_LOG2;
737 if (!InitAstcEncPara(param, imageInfo.size.width, imageInfo.size.height, static_cast<int32_t>(stride), astcOpts_)) {
738 IMAGE_LOGE("InitAstcEncPara failed");
739 return ERROR;
740 }
741 param.enableQualityCheck = enableQualityCheck;
742 AstcEncCheckInfo checkInfo;
743 FillAstcEncCheckInfo(checkInfo, astcPixelMap_, param.astcBytes, 0, 0);
744 if (!CheckAstcEncInput(param, checkInfo)) {
745 IMAGE_LOGE("CheckAstcEncInput failed");
746 return ERROR;
747 }
748 if (!AstcSoftwareEncodeCore(param, pixmapIn, outBuffer)) {
749 IMAGE_LOGE("AstcSoftwareEncodeCore failed");
750 return ERROR;
751 }
752 return SUCCESS;
753 }
754
755 static bool AstcEncProcess(TextureEncodeOptions ¶m, uint8_t *pixmapIn, uint8_t *astcBuffer,
756 AstcEncCheckInfo checkInfo)
757 {
758 if (!CheckAstcEncInput(param, checkInfo)) {
759 IMAGE_LOGE("CheckAstcEncInput failed");
760 return false;
761 }
762 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
763 bool openClEnc = param.width_ >= WIDTH_CL_THRESHOLD && param.height_ >= HEIGHT_CL_THRESHOLD &&
764 param.privateProfile_ == QualityProfile::HIGH_SPEED_PROFILE;
765 bool enableClEnc = openClEnc && ImageSystemProperties::GetGenThumbWithGpu() &&
766 (param.blockX_ == DEFAULT_DIM) && (param.blockY_ == DEFAULT_DIM); // HardWare only support 4x4 now
767 if (enableClEnc) {
768 IMAGE_LOGI("astc hardware encode begin");
769 std::string clBinPath = "/sys_prod/etc/graphic/AstcEncShader_ALN-AL00.bin";
770 if (!CheckClBinIsExistWithLock(clBinPath)) {
771 clBinPath = "/data/storage/el1/base/AstcEncShader.bin";
772 }
773 param.hardwareFlag = AstcCodec::TryAstcEncBasedOnCl(param, pixmapIn, astcBuffer, clBinPath);
774 }
775 #endif
776 if (!param.hardwareFlag) {
777 if (!AstcCodec::AstcSoftwareEncodeCore(param, pixmapIn, astcBuffer)) {
778 IMAGE_LOGE("AstcSoftwareEncodeCore failed");
779 return false;
780 }
781 IMAGE_LOGD("astc software encode success!");
782 }
783 return true;
784 }
785
786 void AstcCodec::InitTextureEncodeOptions(TextureEncodeOptions ¶m, uint8_t &colorData)
787 {
788 param.expandNums = 1;
789 param.extInfoBytes = 1;
790 #ifdef IMAGE_COLORSPACE_FLAG
791 colorData = static_cast<uint8_t>(astcPixelMap_->InnerGetGrColorSpace().GetColorSpaceName());
792 #else
793 colorData = 0;
794 #endif
795 }
796
797 bool AstcCodec::IsAstcEnc(Media::ImageInfo &info, uint8_t* pixelmapIn, TextureEncodeOptions ¶m,
798 AstcExtendInfo &extendInfo)
799 {
800 int32_t bufferSize = astcPixelMap_->GetCapacity();
801 if (bufferSize <= 0) {
802 IMAGE_LOGE("buffer size is less and equal than zero in packing");
803 return false;
804 }
805 if (pixelmapIn == nullptr) {
806 IMAGE_LOGE("pixelmap data is nullptr in packing");
807 return false;
808 }
809 if (info.pixelFormat == PixelFormat::ASTC_4x4 && astcOpts_.format == "image/sdr_astc_4x4") {
810 if (!astcOutput_->Write(pixelmapIn, bufferSize)) {
811 IMAGE_LOGE("fail to write to astcout");
812 return false;
813 }
814 return true;
815 }
816 if (info.pixelFormat == PixelFormat::ASTC_4x4 && astcOpts_.format == "image/sdr_sut_superfast_4x4") {
817 uint8_t *astcBuffer = static_cast<uint8_t *>(malloc(bufferSize));
818 if (astcBuffer == nullptr) {
819 IMAGE_LOGE("Buffer malloc failed in packing");
820 return false;
821 }
822 if (memcpy_s(astcBuffer, bufferSize, pixelmapIn, bufferSize) < 0) {
823 IMAGE_LOGE("Copy data failed in packing");
824 free(astcBuffer);
825 return false;
826 }
827 if (!TryEncSUT(param, astcBuffer, extendInfo)) {
828 IMAGE_LOGE("Astc encode sut failed in packing");
829 return false;
830 }
831 bufferSize = static_cast<uint32_t>(param.sutBytes);
832 if (!astcOutput_->Write(astcBuffer, bufferSize)) {
833 IMAGE_LOGE("Write to astcout failed in packing");
834 free(astcBuffer);
835 return false;
836 }
837 free(astcBuffer);
838 return true;
839 }
840 IMAGE_LOGE("Does not support packing format");
841 return false;
842 }
843
844 bool AstcCodec::InitBeforeAstcEncode(ImageInfo &imageInfo, TextureEncodeOptions ¶m, uint8_t &colorData,
845 uint8_t **pixmapIn, uint32_t &stride)
846 {
847 if (astcPixelMap_ == nullptr || astcOutput_ == nullptr) {
848 return false;
849 }
850 astcPixelMap_->GetImageInfo(imageInfo);
851 InitTextureEncodeOptions(param, colorData);
852 param.extInfoBuf = &colorData;
853 *pixmapIn = const_cast<uint8_t *>(astcPixelMap_->GetPixels());
854 stride = static_cast<uint32_t>(astcPixelMap_->GetRowStride()) >> RGBA_BYTES_PIXEL_LOG2;
855 if (!InitAstcEncPara(param, imageInfo.size.width, imageInfo.size.height, static_cast<int32_t>(stride), astcOpts_)) {
856 IMAGE_LOGE("InitAstcEncPara failed");
857 return false;
858 }
859 return true;
860 }
861
862 bool AstcCodec::TryEncSUT(TextureEncodeOptions ¶m, uint8_t* astcBuffer, AstcExtendInfo &extendInfo)
863 {
864 #ifdef SUT_ENCODE_ENABLE
865 if (!TryTextureSuperCompress(param, astcBuffer)) {
866 IMAGE_LOGE("astc TryTextureSuperCompress failed!");
867 ReleaseExtendInfoMemory(extendInfo);
868 free(astcBuffer);
869 return false;
870 }
871 return true;
872 #else
873 return true;
874 #endif
875 }
876
877 uint32_t AstcCodec::ASTCEncode() __attribute__((no_sanitize("cfi")))
878 {
879 ImageInfo imageInfo;
880 TextureEncodeOptions param;
881 uint8_t colorData;
882 uint8_t *pixmapIn = nullptr;
883 uint32_t stride = 0;
884 if (!InitBeforeAstcEncode(imageInfo, param, colorData, &pixmapIn, stride)) {
885 return ERROR;
886 }
887 ImageTrace("[AstcCodec] ASTCEncode Size: %d, %d", imageInfo.size.width, imageInfo.size.height);
888 AstcExtendInfo extendInfo = {0};
889 if (!InitAstcExtendInfo(extendInfo)) {
890 return ERROR;
891 }
892 uint32_t packSize = static_cast<uint32_t>(param.astcBytes) + extendInfo.extendBufferSumBytes + ASTC_NUM_4;
893 if (astcPixelMap_->IsAstc()) {
894 if (!IsAstcEnc(imageInfo, pixmapIn, param, extendInfo)) {
895 return ERROR;
896 }
897 return SUCCESS;
898 }
899 uint8_t *astcBuffer = static_cast<uint8_t *>(malloc(packSize));
900 if (astcBuffer == nullptr) {
901 ReleaseExtendInfoMemory(extendInfo);
902 return ERROR;
903 }
904 AstcEncCheckInfo checkInfo;
905 FillAstcEncCheckInfo(checkInfo, astcPixelMap_, packSize, ASTC_NUM_4, extendInfo.extendBufferSumBytes);
906 if (!AstcEncProcess(param, pixmapIn, astcBuffer, checkInfo)) {
907 IMAGE_LOGE("astc AstcEncProcess failed!");
908 ReleaseExtendInfoMemory(extendInfo);
909 free(astcBuffer);
910 return ERROR;
911 }
912 if (!TryEncSUT(param, astcBuffer, extendInfo)) {
913 return ERROR;
914 }
915 if (!param.outIsSut) { // only support astc for color space
916 WriteAstcExtendInfo(astcBuffer, static_cast<uint32_t>(param.astcBytes), extendInfo);
917 } else {
918 packSize = static_cast<uint32_t>(param.sutBytes);
919 }
920 ReleaseExtendInfoMemory(extendInfo);
921 if (!astcOutput_->Write(astcBuffer, packSize)) {
922 free(astcBuffer);
923 return ERROR;
924 }
925 free(astcBuffer);
926 IMAGE_LOGD("astcenc end: %{public}dx%{public}d, GpuFlag %{public}d, sut%{public}d",
927 imageInfo.size.width, imageInfo.size.height, param.hardwareFlag, param.sutProfile);
928 astcOutput_->SetOffset(packSize);
929 return SUCCESS;
930 }
931
932 bool AllocMemForExtInfo(AstcExtendInfo &extendInfo, uint8_t idx)
933 {
934 auto AllocAndCopy = [&](size_t dataSize, const void* srcData, const char* logTag) -> bool {
935 extendInfo.extendInfoLength[idx] = static_cast<uint32_t>(dataSize);
936 extendInfo.extendBufferSumBytes += ASTC_EXTEND_INFO_TYPE_LENGTH +
937 ASTC_EXTEND_INFO_LENGTH_LENGTH +
938 extendInfo.extendInfoLength[idx];
939 if (dataSize <= 0) {
940 return false;
941 }
942 extendInfo.extendInfoValue[idx] = static_cast<uint8_t*>(malloc(dataSize));
943 if (extendInfo.extendInfoValue[idx] == nullptr) {
944 IMAGE_LOGE("[AstcCodec] %s malloc failed!", logTag);
945 return false;
946 }
947 if (srcData && memcpy_s(extendInfo.extendInfoValue[idx], dataSize,
948 srcData, dataSize) != 0) {
949 IMAGE_LOGE("[AstcCodec] %s memcpy failed!", logTag);
950 return false;
951 }
952 return true;
953 };
954 AstcExtendInfoType type = static_cast<AstcExtendInfoType>(idx);
955 switch (type) {
956 case AstcExtendInfoType::COLOR_SPACE:
957 case AstcExtendInfoType::PIXEL_FORMAT:
958 // These types only require memory allocation and do not require data initialization
959 return AllocAndCopy(ASTC_EXTEND_INFO_COLOR_SPACE_VALUE_LENGTH,
960 nullptr, type == AstcExtendInfoType::COLOR_SPACE ?
961 "SetColorSpaceInfo" : "SetPixelFormatInfo");
962 case AstcExtendInfoType::HDR_METADATA_TYPE:
963 return AllocAndCopy(extendInfo.astcMetadata.hdrMetadataTypeVec.size(),
964 extendInfo.astcMetadata.hdrMetadataTypeVec.data(),
965 "SetHdrMetadataType");
966 case AstcExtendInfoType::HDR_COLORSPACE_INFO:
967 return AllocAndCopy(extendInfo.astcMetadata.colorSpaceInfoVec.size(),
968 extendInfo.astcMetadata.colorSpaceInfoVec.data(),
969 "SetHdrColorSpaceInfo");
970 case AstcExtendInfoType::HDR_STATIC_DATA:
971 return AllocAndCopy(extendInfo.astcMetadata.staticData.size(),
972 extendInfo.astcMetadata.staticData.data(),
973 "SetHdrStaticData");
974 case AstcExtendInfoType::HDR_DYNAMIC_DATA:
975 return AllocAndCopy(extendInfo.astcMetadata.dynamicData.size(),
976 extendInfo.astcMetadata.dynamicData.data(),
977 "SetHdrDynamicData");
978 default:
979 IMAGE_LOGE("[AstcCodec] Unknown extend info type: %d", static_cast<int>(type));
980 return false;
981 }
982 }
983
984 bool AstcCodec::FillMetaData(AstcExtendInfo &extendInfo, PixelMap *astcPixelMap)
985 {
986 if (astcPixelMap == nullptr || astcPixelMap->GetFd() == nullptr ||
987 astcPixelMap->GetAllocatorType() != AllocatorType::DMA_ALLOC) {
988 IMAGE_LOGE("[AstcCodec] astcPixelMap is invalid!");
989 return false;
990 }
991 if (!astcPixelMap->IsHdr()) {
992 return false; // No need to fill metadata for SDR
993 }
994 sptr<SurfaceBuffer> source(reinterpret_cast<SurfaceBuffer *>(astcPixelMap->GetFd()));
995 bool baseMetadataSuccess = true;
996 bool vpeMetadataSuccess = true; // Track static/dynamic metadata status separately
997
998 auto CheckResult = [&](GSError status, const char* metadataName) {
999 if (status != GSERROR_OK) {
1000 IMAGE_LOGE("[AstcCodec] GetMetadata %{public}s failed: %{public}d", metadataName, status);
1001 baseMetadataSuccess = false;
1002 }
1003 };
1004 CheckResult(source->GetMetadata(ATTRKEY_HDR_METADATA_TYPE,
1005 extendInfo.astcMetadata.hdrMetadataTypeVec), "ATTRKEY_HDR_METADATA_TYPE");
1006 CheckResult(source->GetMetadata(ATTRKEY_COLORSPACE_INFO,
1007 extendInfo.astcMetadata.colorSpaceInfoVec), "ATTRKEY_COLORSPACE_INFO");
1008 // Check if required metadata is filled
1009 if (!baseMetadataSuccess) {
1010 IMAGE_LOGE("[AstcCodec] Critical base metadata missing!");
1011 return false;
1012 }
1013
1014 auto CheckVpeResult = [&](bool result, const char* metadataName, auto& dataVec) {
1015 if (!result || dataVec.empty()) {
1016 IMAGE_LOGE("[AstcCodec] %{public}s failed or empty", metadataName);
1017 vpeMetadataSuccess = false; // Only marking failures does not affect the basic metadata status
1018 }
1019 };
1020 // Check static/dynamic metadata (non critical)
1021 CheckVpeResult(VpeUtils::GetSbStaticMetadata(source, extendInfo.astcMetadata.staticData),
1022 "GetSbStaticMetadata", extendInfo.astcMetadata.staticData);
1023 CheckVpeResult(VpeUtils::GetSbDynamicMetadata(source, extendInfo.astcMetadata.dynamicData),
1024 "GetSbDynamicMetadata", extendInfo.astcMetadata.dynamicData);
1025
1026 // Dynamically set extendNums based on VP metadata results
1027 extendInfo.extendNums = vpeMetadataSuccess ? ASTC_EXTEND_INFO_TLV_NUM_6 : ASTC_EXTEND_INFO_TLV_NUM_4;
1028
1029 IMAGE_LOGI("[AstcCodec] HDR metadata: base=%{public}s, VP=%{public}s, using extendNums=%{public}d",
1030 baseMetadataSuccess ? "success" : "fail",
1031 vpeMetadataSuccess ? "success" : "fail",
1032 extendInfo.extendNums);
1033 return true;
1034 }
1035
1036 bool AstcCodec::InitAstcExtendInfo(AstcExtendInfo &extendInfo)
1037 {
1038 if (memset_s(&extendInfo, sizeof(AstcExtendInfo), 0, sizeof(AstcExtendInfo)) != 0) {
1039 IMAGE_LOGE("[AstcCodec] memset extendInfo failed!");
1040 return false;
1041 }
1042 extendInfo.extendNums = astcPixelMap_->IsHdr() ? ASTC_EXTEND_INFO_TLV_NUM_6 : ASTC_EXTEND_INFO_TLV_NUM;
1043 extendInfo.extendBufferSumBytes = 0;
1044 if (astcPixelMap_->IsHdr()) {
1045 if (!FillMetaData(extendInfo, astcPixelMap_)) {
1046 IMAGE_LOGE("[AstcCodec] FillMetaData failed!");
1047 return false;
1048 }
1049 }
1050 for (uint8_t idx = 0; idx < extendInfo.extendNums; idx++) {
1051 if (!AllocMemForExtInfo(extendInfo, idx)) {
1052 ReleaseExtendInfoMemory(extendInfo);
1053 IMAGE_LOGE("[AstcCodec] AllocMemForExtInfo failed!");
1054 return false;
1055 }
1056 }
1057 return true;
1058 }
1059
1060 void AstcCodec::ReleaseExtendInfoMemory(AstcExtendInfo &extendInfo)
1061 {
1062 for (uint8_t idx = 0; idx < extendInfo.extendNums; idx++) {
1063 if (extendInfo.extendInfoValue[idx] != nullptr) {
1064 free(extendInfo.extendInfoValue[idx]);
1065 extendInfo.extendInfoValue[idx] = nullptr;
1066 }
1067 }
1068 }
1069
1070 static void FillDataSize(uint8_t *buf, uint32_t bytes)
1071 {
1072 *buf++ = (bytes) & MASKBITS_FOR_8BITS;
1073 *buf++ = (bytes >> UINT32_1TH_BYTES) & MASKBITS_FOR_8BITS;
1074 *buf++ = (bytes >> UINT32_2TH_BYTES) & MASKBITS_FOR_8BITS;
1075 *buf++ = (bytes >> UINT32_3TH_BYTES) & MASKBITS_FOR_8BITS;
1076 }
1077
1078 void AstcCodec::WriteAstcExtendInfo(uint8_t *buffer, uint32_t offset, AstcExtendInfo &extendInfo)
1079 {
1080 uint8_t* offsetBuffer = buffer + offset;
1081 FillDataSize(offsetBuffer, extendInfo.extendBufferSumBytes);
1082 offsetBuffer += ASTC_EXTEND_INFO_SIZE_DEFINITION_LENGTH;
1083 #ifdef IMAGE_COLORSPACE_FLAG
1084 ColorManager::ColorSpace colorspace = astcPixelMap_->InnerGetGrColorSpace();
1085 ColorManager::ColorSpaceName csName = colorspace.GetColorSpaceName();
1086 #endif
1087 PixelFormat pixelFormat = astcPixelMap_->GetPixelFormat();
1088 for (uint8_t idx = 0; idx < extendInfo.extendNums; idx++) {
1089 *offsetBuffer++ = idx;
1090 FillDataSize(offsetBuffer, extendInfo.extendInfoLength[idx]);
1091 offsetBuffer += ASTC_EXTEND_INFO_LENGTH_LENGTH;
1092 AstcExtendInfoType type = static_cast<AstcExtendInfoType>(idx);
1093 switch (type) {
1094 case AstcExtendInfoType::COLOR_SPACE:
1095 #ifdef IMAGE_COLORSPACE_FLAG
1096 *offsetBuffer = static_cast<uint8_t>(csName);
1097 #else
1098 *offsetBuffer = 0;
1099 #endif
1100 offsetBuffer += ASTC_EXTEND_INFO_COLOR_SPACE_VALUE_LENGTH;
1101 break;
1102 case AstcExtendInfoType::PIXEL_FORMAT:
1103 *offsetBuffer = static_cast<uint8_t>(pixelFormat);
1104 offsetBuffer += ASTC_EXTEND_INFO_PIXEL_FORMAT_VALUE_LENGTH;
1105 break;
1106 case AstcExtendInfoType::HDR_METADATA_TYPE:
1107 case AstcExtendInfoType::HDR_COLORSPACE_INFO:
1108 case AstcExtendInfoType::HDR_STATIC_DATA:
1109 case AstcExtendInfoType::HDR_DYNAMIC_DATA:
1110 if (extendInfo.extendInfoValue[idx] == nullptr||
1111 extendInfo.extendInfoLength[idx] <= 0 ||
1112 memcpy_s(offsetBuffer, extendInfo.extendInfoLength[idx],
1113 extendInfo.extendInfoValue[idx], extendInfo.extendInfoLength[idx]) != 0) {
1114 IMAGE_LOGE("[AstcCodec] WriteAstcExtendInfo memcpy failed!");
1115 return;
1116 }
1117 offsetBuffer += extendInfo.extendInfoLength[idx];
1118 break;
1119 default:
1120 return;
1121 }
1122 }
1123 }
1124 } // namespace ImagePlugin
1125 } // namespace OHOS
1126