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
19 #include "astc_codec.h"
20 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
21 #include "image_compressor.h"
22 #endif
23 #include "image_log.h"
24 #include "image_system_properties.h"
25 #include "securec.h"
26 #include "media_errors.h"
27
28 #undef LOG_DOMAIN
29 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
30
31 #undef LOG_TAG
32 #define LOG_TAG "AstcCodec"
33
34 namespace OHOS {
35 namespace ImagePlugin {
36 using namespace Media;
37 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
38 using namespace AstcEncBasedCl;
39 #endif
40 constexpr uint8_t TEXTURE_HEAD_BYTES = 16;
41 constexpr uint8_t ASTC_MASK = 0xFF;
42 constexpr uint8_t ASTC_NUM_8 = 8;
43 constexpr uint8_t ASTC_HEADER_SIZE = 16;
44 constexpr uint8_t ASTC_NUM_24 = 24;
45 static const uint32_t ASTC_MAGIC_ID = 0x5CA1AB13;
46 constexpr uint8_t DEFAULT_DIM = 4;
47 constexpr uint8_t HIGH_SPEED_PROFILE_MAP_QUALITY = 20; // quality level is 20 for thumbnail
48 constexpr uint8_t RGBA_BYTES_PIXEL_LOG2 = 2;
49 constexpr uint8_t MASKBITS_FOR_8BITS = 255;
50 constexpr uint8_t UINT32_1TH_BYTES = 8;
51 constexpr uint8_t UINT32_2TH_BYTES = 16;
52 constexpr uint8_t UINT32_3TH_BYTES = 24;
53 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
54 constexpr int32_t WIDTH_CL_THRESHOLD = 256;
55 constexpr int32_t HEIGHT_CL_THRESHOLD = 256;
56 #endif
57
58 #if (defined SUT_ENCODE_ENABLE) || (defined ENABLE_ASTC_ENCODE_BASED_GPU)
CheckClBinIsExist(const std::string & name)59 static bool CheckClBinIsExist(const std::string &name)
60 {
61 return (access(name.c_str(), F_OK) != -1); // -1 means that the file is not exist
62 }
63 #endif
64
65 #ifdef SUT_ENCODE_ENABLE
66 static const std::string g_textureSuperEncSo = "/system/lib64/module/hms/graphic/libtextureSuperCompress.z.so";
67 using SuperCompressTexture = bool (*)(uint8_t*, int32_t, uint8_t*, int32_t&, uint32_t);
68
69 class SutEncSoManager {
70 public:
71 SutEncSoManager();
72 ~SutEncSoManager();
73 bool LoadSutEncSo();
74 SuperCompressTexture sutEncSoEncFunc_;
75 private:
76 bool sutEncSoOpened_;
77 void *textureEncSoHandle_;
78 };
79
80 static SutEncSoManager g_sutEncSoManager;
81
SutEncSoManager()82 SutEncSoManager::SutEncSoManager()
83 {
84 sutEncSoOpened_ = false;
85 textureEncSoHandle_ = nullptr;
86 sutEncSoEncFunc_ = nullptr;
87 }
88
~SutEncSoManager()89 SutEncSoManager::~SutEncSoManager()
90 {
91 bool sutEncHasBeenOpen = sutEncSoOpened_ && (textureEncSoHandle_ != nullptr);
92 if (sutEncHasBeenOpen) {
93 int ret = dlclose(textureEncSoHandle_);
94 IMAGE_LOGD("astcenc dlcose ret: %{public}d %{public}s!", ret, g_textureSuperEncSo.c_str());
95 }
96 }
97
LoadSutEncSo()98 bool SutEncSoManager::LoadSutEncSo()
99 {
100 if (!sutEncSoOpened_) {
101 if (!CheckClBinIsExist(g_textureSuperEncSo)) {
102 IMAGE_LOGE("sut %{public}s! is not found", g_textureSuperEncSo.c_str());
103 return false;
104 }
105 textureEncSoHandle_ = dlopen(g_textureSuperEncSo.c_str(), 1);
106 if (textureEncSoHandle_ == nullptr) {
107 IMAGE_LOGE("sut libtextureSuperCompress dlopen failed!");
108 return false;
109 }
110 sutEncSoEncFunc_ =
111 reinterpret_cast<SuperCompressTexture>(dlsym(textureEncSoHandle_, "SuperCompressTexture"));
112 if (sutEncSoEncFunc_ == nullptr) {
113 IMAGE_LOGE("sut libtextureSuperCompress dlsym failed!");
114 dlclose(textureEncSoHandle_);
115 textureEncSoHandle_ = nullptr;
116 return false;
117 }
118 IMAGE_LOGD("astcenc dlopen success: %{public}s!", g_textureSuperEncSo.c_str());
119 sutEncSoOpened_ = true;
120 }
121 return true;
122 }
123 #endif
124
SetAstcEncode(OutputDataStream * outputStream,PlEncodeOptions & option,Media::PixelMap * pixelMap)125 uint32_t AstcCodec::SetAstcEncode(OutputDataStream* outputStream, PlEncodeOptions &option, Media::PixelMap* pixelMap)
126 {
127 if (outputStream == nullptr || pixelMap == nullptr) {
128 IMAGE_LOGE("input data is nullptr.");
129 return ERROR;
130 }
131 astcOutput_ = outputStream;
132 astcOpts_ = option;
133 astcPixelMap_ = pixelMap;
134 return SUCCESS;
135 }
136
137 // test ASTCEncoder
GenAstcHeader(uint8_t * header,astcenc_image img,TextureEncodeOptions & encodeParams)138 uint32_t GenAstcHeader(uint8_t *header, astcenc_image img, TextureEncodeOptions &encodeParams)
139 {
140 uint8_t *tmp = header;
141 *tmp++ = ASTC_MAGIC_ID & ASTC_MASK;
142 *tmp++ = (ASTC_MAGIC_ID >> ASTC_NUM_8) & ASTC_MASK;
143 *tmp++ = (ASTC_MAGIC_ID >> ASTC_HEADER_SIZE) & ASTC_MASK;
144 *tmp++ = (ASTC_MAGIC_ID >> ASTC_NUM_24) & ASTC_MASK;
145 *tmp++ = static_cast<uint8_t>(encodeParams.blockX_);
146 *tmp++ = static_cast<uint8_t>(encodeParams.blockY_);
147 *tmp++ = 1;
148 *tmp++ = img.dim_x & ASTC_MASK;
149 *tmp++ = (img.dim_x >> ASTC_NUM_8) & ASTC_MASK;
150 *tmp++ = (img.dim_x >> ASTC_HEADER_SIZE) & ASTC_MASK;
151 *tmp++ = img.dim_y & ASTC_MASK;
152 *tmp++ = (img.dim_y >> ASTC_NUM_8) & ASTC_MASK;
153 *tmp++ = (img.dim_y >> ASTC_HEADER_SIZE) & ASTC_MASK;
154 *tmp++ = img.dim_z & ASTC_MASK;
155 *tmp++ = (img.dim_z >> ASTC_NUM_8) & ASTC_MASK;
156 *tmp++ = (img.dim_z >> ASTC_HEADER_SIZE) & ASTC_MASK;
157 return SUCCESS;
158 }
159
InitAstcencConfig(AstcEncoder * work,TextureEncodeOptions * option)160 uint32_t InitAstcencConfig(AstcEncoder* work, TextureEncodeOptions* option)
161 {
162 bool invalidInput = (work == nullptr) || (option == nullptr);
163 if (invalidInput) {
164 IMAGE_LOGE("astc input work or option is nullptr.");
165 return ERROR;
166 }
167 unsigned int blockX = option->blockX_;
168 unsigned int blockY = option->blockY_;
169 unsigned int blockZ = 1;
170
171 float quality = ASTCENC_PRE_FAST;
172 unsigned int flags = ASTCENC_FLG_SELF_DECOMPRESS_ONLY;
173 astcenc_error status = astcenc_config_init(work->profile, blockX, blockY,
174 blockZ, quality, flags, &work->config);
175 if (status != ASTCENC_SUCCESS) {
176 IMAGE_LOGE("ERROR: astcenc_config_init failed, status %{public}d", status);
177 return ERROR;
178 }
179 work->config.privateProfile = option->privateProfile_;
180 if (work->config.privateProfile == HIGH_SPEED_PROFILE) {
181 work->config.tune_refinement_limit = 1;
182 work->config.tune_candidate_limit = 1;
183 work->config.tune_partition_count_limit = 1;
184 }
185 if (astcenc_context_alloc(&work->config, 1, &work->codec_context) != ASTCENC_SUCCESS) {
186 return ERROR;
187 }
188 return SUCCESS;
189 }
190
extractDimensions(std::string & format,TextureEncodeOptions & param)191 void extractDimensions(std::string &format, TextureEncodeOptions ¶m)
192 {
193 param.blockX_ = DEFAULT_DIM;
194 param.blockY_ = DEFAULT_DIM;
195 std::size_t slashPos = format.rfind('/');
196 if (slashPos != std::string::npos) {
197 std::string dimensions = format.substr(slashPos + 1);
198 std::size_t starPos = dimensions.find('*');
199 if (starPos != std::string::npos) {
200 std::string widthStr = dimensions.substr(0, starPos);
201 std::string heightStr = dimensions.substr(starPos + 1);
202
203 auto ret_x = std::from_chars(widthStr.data(), widthStr.data() + widthStr.size(), param.blockX_);
204 auto ret_y = std::from_chars(heightStr.data(), heightStr.data() + heightStr.size(), param.blockY_);
205 if (!(ret_x.ec == std::errc() && ret_y.ec == std::errc())) {
206 IMAGE_LOGE("Failed to convert string to number");
207 }
208 }
209 }
210 }
211
212 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
213 constexpr double MAX_PSNR = 99.9;
214 constexpr double MAX_VALUE = 255;
215 constexpr double THRESHOLD_R = 30.0;
216 constexpr double THRESHOLD_G = 30.0;
217 constexpr double THRESHOLD_B = 30.0;
218 constexpr double THRESHOLD_A = 30.0;
219 constexpr double THRESHOLD_RGB = 30.0;
220 constexpr double LOG_BASE = 10.0;
CheckQuality(int32_t * mseIn[RGBA_COM],int blockNum,int blockXYZ)221 bool CheckQuality(int32_t *mseIn[RGBA_COM], int blockNum, int blockXYZ)
222 {
223 double psnr[RGBA_COM + 1];
224 const double threshold[RGBA_COM + 1] = {THRESHOLD_R, THRESHOLD_G, THRESHOLD_B, THRESHOLD_A, THRESHOLD_RGB};
225 uint64_t mseTotal[RGBA_COM + 1] = {0, 0, 0, 0, 0};
226 for (int i = R_COM; i < RGBA_COM; i++) {
227 int32_t *mse = mseIn[i];
228 if (!mse) {
229 return false;
230 }
231 for (int j = 0; j < blockNum; j++) {
232 mseTotal[i] += *mse;
233 if (i != A_COM) mseTotal[RGBA_COM] += *mse;
234 mse++;
235 }
236 }
237 for (int i = R_COM; i < RGBA_COM; i++) {
238 if (mseTotal[i] == 0) {
239 psnr[i] = MAX_PSNR;
240 continue;
241 }
242 double mseRgb = static_cast<double>(mseTotal[i] / static_cast<uint64_t>((blockNum * blockXYZ)));
243 psnr[i] = LOG_BASE * log(static_cast<double>(MAX_VALUE * MAX_VALUE) / mseRgb) / log(LOG_BASE);
244 }
245 if (mseTotal[RGBA_COM] == 0) {
246 psnr[RGBA_COM] = MAX_PSNR;
247 } else {
248 double mseRgb = static_cast<double>(
249 mseTotal[RGBA_COM] / static_cast<uint64_t>((blockNum * blockXYZ * (RGBA_COM - 1))));
250 psnr[RGBA_COM] = LOG_BASE * log(static_cast<double>(MAX_VALUE * MAX_VALUE) / mseRgb) / log(LOG_BASE);
251 }
252 IMAGE_LOGD("astc psnr r%{public}f g%{public}f b%{public}f a%{public}f rgb%{public}f",
253 psnr[R_COM], psnr[G_COM], psnr[B_COM], psnr[A_COM],
254 psnr[RGBA_COM]);
255 return (psnr[R_COM] > threshold[R_COM]) && (psnr[G_COM] > threshold[G_COM])
256 && (psnr[B_COM] > threshold[B_COM]) && (psnr[A_COM] > threshold[A_COM])
257 && (psnr[RGBA_COM] > threshold[RGBA_COM]);
258 }
259 #endif
260
FreeMem(AstcEncoder * work)261 static void FreeMem(AstcEncoder *work)
262 {
263 if (!work) {
264 return;
265 }
266 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
267 if (work->calQualityEnable) {
268 for (int i = R_COM; i < RGBA_COM; i++) {
269 if (work->mse[i]) {
270 free(work->mse[i]);
271 work->mse[i] = nullptr;
272 }
273 }
274 }
275 #endif
276 if (work->image_.data) {
277 free(work->image_.data);
278 work->image_.data = nullptr;
279 }
280 if (work->codec_context != nullptr) {
281 astcenc_context_free(work->codec_context);
282 work->codec_context = nullptr;
283 }
284 work->data_out_ = nullptr;
285 }
286
InitMem(AstcEncoder * work,TextureEncodeOptions param)287 static bool InitMem(AstcEncoder *work, TextureEncodeOptions param)
288 {
289 if (!work) {
290 return false;
291 }
292 work->swizzle_ = {ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A};
293 work->image_.dim_x = static_cast<unsigned int>(param.width_);
294 work->image_.dim_y = static_cast<unsigned int>(param.height_);
295 work->image_.dim_z = 1;
296 work->image_.data_type = ASTCENC_TYPE_U8;
297 work->image_.dim_stride = static_cast<unsigned int>(param.stride_);
298 work->codec_context = nullptr;
299 work->image_.data = nullptr;
300 work->profile = ASTCENC_PRF_LDR_SRGB;
301 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
302 work->mse[R_COM] = work->mse[G_COM] = work->mse[B_COM] = work->mse[RGBA_COM] = nullptr;
303 work->calQualityEnable = param.enableQualityCheck;
304 if (work->calQualityEnable) {
305 for (int i = R_COM; i < RGBA_COM; i++) {
306 work->mse[i] = static_cast<int32_t *>(calloc(param.blocksNum, sizeof(int32_t)));
307 if (!work->mse[i]) {
308 IMAGE_LOGE("quality control calloc failed");
309 return false;
310 }
311 }
312 }
313 #endif
314 work->image_.data = static_cast<void **>(malloc(sizeof(void*) * work->image_.dim_z));
315 if (!work->image_.data) {
316 return false;
317 }
318 return true;
319 }
320
AstcSoftwareEncodeCore(TextureEncodeOptions & param,uint8_t * pixmapIn,uint8_t * astcBuffer)321 bool AstcCodec::AstcSoftwareEncodeCore(TextureEncodeOptions ¶m, uint8_t *pixmapIn, uint8_t *astcBuffer)
322 {
323 if ((pixmapIn == nullptr) || (astcBuffer == nullptr)) {
324 IMAGE_LOGE("pixmapIn or astcBuffer is nullptr");
325 return false;
326 }
327 AstcEncoder work;
328 if (!InitMem(&work, param)) {
329 FreeMem(&work);
330 return false;
331 }
332 if (InitAstcencConfig(&work, ¶m) != SUCCESS) {
333 IMAGE_LOGE("astc InitAstcencConfig failed");
334 FreeMem(&work);
335 return false;
336 }
337 work.image_.data[0] = pixmapIn;
338 work.data_out_ = astcBuffer;
339 if (GenAstcHeader(work.data_out_, work.image_, param) != SUCCESS) {
340 IMAGE_LOGE("astc GenAstcHeader failed");
341 FreeMem(&work);
342 return false;
343 }
344 work.error_ = astcenc_compress_image(work.codec_context, &work.image_, &work.swizzle_,
345 work.data_out_ + TEXTURE_HEAD_BYTES, param.astcBytes - TEXTURE_HEAD_BYTES,
346 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
347 work.calQualityEnable, work.mse,
348 #endif
349 0);
350 #if defined(QUALITY_CONTROL) && (QUALITY_CONTROL == 1)
351 if ((ASTCENC_SUCCESS != work.error_) ||
352 (work.calQualityEnable && !CheckQuality(work.mse, param.blocksNum, param.blockX_ * param.blockY_))) {
353 #else
354 if (ASTCENC_SUCCESS != work.error_) {
355 #endif
356 IMAGE_LOGE("astc compress failed");
357 FreeMem(&work);
358 return false;
359 }
360 FreeMem(&work);
361 return true;
362 }
363
364 static QualityProfile GetAstcQuality(int32_t quality)
365 {
366 QualityProfile privateProfile;
367 switch (quality) {
368 case HIGH_SPEED_PROFILE_MAP_QUALITY:
369 privateProfile = HIGH_SPEED_PROFILE;
370 break;
371 default:
372 privateProfile = HIGH_QUALITY_PROFILE;
373 break;
374 }
375 return privateProfile;
376 }
377
378 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
379 bool AstcCodec::TryAstcEncBasedOnCl(TextureEncodeOptions ¶m, uint8_t *inData,
380 uint8_t *buffer, const std::string &clBinPath)
381 {
382 ClAstcHandle *astcClEncoder = nullptr;
383 bool invalidPara = (inData == nullptr) || (buffer == nullptr);
384 if (invalidPara) {
385 IMAGE_LOGE("astc Please check TryAstcEncBasedOnCl input!");
386 return false;
387 }
388 if (AstcClCreate(&astcClEncoder, clBinPath) != CL_ASTC_ENC_SUCCESS) {
389 IMAGE_LOGE("astc AstcClCreate failed!");
390 return false;
391 }
392 ClAstcImageOption imageIn;
393 if (AstcClFillImage(&imageIn, inData, param.stride_, param.width_, param.height_) != CL_ASTC_ENC_SUCCESS) {
394 IMAGE_LOGE("astc AstcClFillImage failed!");
395 AstcClClose(astcClEncoder);
396 return false;
397 }
398 if (AstcClEncImage(astcClEncoder, &imageIn, buffer) != CL_ASTC_ENC_SUCCESS) {
399 IMAGE_LOGE("astc AstcClEncImage failed!");
400 AstcClClose(astcClEncoder);
401 return false;
402 }
403 if (AstcClClose(astcClEncoder) != CL_ASTC_ENC_SUCCESS) {
404 IMAGE_LOGE("astc AstcClClose failed!");
405 return false;
406 }
407 return true;
408 }
409 #endif
410
411 #ifdef SUT_ENCODE_ENABLE
412 bool AstcCodec::TryTextureSuperCompress(TextureEncodeOptions ¶m, uint8_t *astcBuffer)
413 {
414 bool skipSutEnc = (param.sutProfile == SutProfile::SKIP_SUT) ||
415 ((!param.hardwareFlag) && (param.privateProfile_ != HIGH_SPEED_PROFILE)) ||
416 (param.blockX_ != DEFAULT_DIM && param.blockY_ != DEFAULT_DIM);
417 if (skipSutEnc) {
418 IMAGE_LOGD("astc is not suit to be compressed to sut!");
419 param.sutProfile = SutProfile::SKIP_SUT;
420 return true;
421 }
422 param.sutBytes = param.astcBytes;
423 uint8_t *sutBuffer = static_cast<uint8_t *>(malloc(param.sutBytes));
424 if (sutBuffer == nullptr) {
425 IMAGE_LOGE("astc sutBuffer malloc failed!");
426 return false;
427 }
428 bool invalidSutEnc = !g_sutEncSoManager.LoadSutEncSo() || g_sutEncSoManager.sutEncSoEncFunc_ == nullptr;
429 if (invalidSutEnc) {
430 IMAGE_LOGE("sut enc so dlopen failed or sutEncSoEncFunc_ is nullptr!");
431 free(sutBuffer);
432 return false;
433 }
434 if (!g_sutEncSoManager.sutEncSoEncFunc_(astcBuffer,
435 param.astcBytes, sutBuffer, param.sutBytes, static_cast<uint32_t>(param.sutProfile))) {
436 IMAGE_LOGE("astc g_sutEncSoEncFunc failed!");
437 free(sutBuffer);
438 return false;
439 }
440 if (memcpy_s(astcBuffer, param.astcBytes, sutBuffer, param.sutBytes) < 0) {
441 IMAGE_LOGE("sut sutbuffer is failed to be copied to astcBuffer!");
442 free(sutBuffer);
443 return false;
444 }
445 free(sutBuffer);
446 param.astcBytes = param.sutBytes;
447 param.outIsSut = true;
448 return true;
449 }
450 #endif
451
452 static bool InitAstcEncPara(TextureEncodeOptions ¶m,
453 int32_t width, int32_t height, int32_t stride, PlEncodeOptions &astcOpts)
454 {
455 param.enableQualityCheck = false;
456 param.hardwareFlag = false;
457 param.sutProfile =
458 ImageSystemProperties::GetSutEncodeEnabled() ? SutProfile::EXTREME_SPEED : SutProfile::SKIP_SUT;
459 param.width_ = width;
460 param.height_ = height;
461 param.stride_ = stride;
462 param.privateProfile_ = GetAstcQuality(astcOpts.quality);
463 param.outIsSut = false;
464 extractDimensions(astcOpts.format, param);
465 if ((param.blockX_ < DEFAULT_DIM) || (param.blockY_ < DEFAULT_DIM)) { // DEFAULT_DIM = 4
466 IMAGE_LOGE("InitAstcEncPara failed %{public}dx%{public}d is invalid!", param.blockX_, param.blockY_);
467 return false;
468 }
469 param.blocksNum = ((param.width_ + param.blockX_ - 1) / param.blockX_) *
470 ((param.height_ + param.blockY_ - 1) / param.blockY_);
471 param.astcBytes = param.blocksNum * TEXTURE_HEAD_BYTES + TEXTURE_HEAD_BYTES;
472 return true;
473 }
474
475 uint32_t AstcCodec::AstcSoftwareEncode(TextureEncodeOptions ¶m, bool enableQualityCheck,
476 int32_t blocksNum, uint8_t *outBuffer, int32_t outSize)
477 {
478 ImageInfo imageInfo;
479 astcPixelMap_->GetImageInfo(imageInfo);
480 uint8_t *pixmapIn = static_cast<uint8_t *>(astcPixelMap_->GetWritablePixels());
481 uint32_t stride = static_cast<uint32_t>(astcPixelMap_->GetRowStride()) >> RGBA_BYTES_PIXEL_LOG2;
482 if (!InitAstcEncPara(param, imageInfo.size.width, imageInfo.size.height, static_cast<int32_t>(stride), astcOpts_)) {
483 IMAGE_LOGE("InitAstcEncPara failed");
484 return ERROR;
485 }
486 param.enableQualityCheck = enableQualityCheck;
487 if (!AstcSoftwareEncodeCore(param, pixmapIn, outBuffer)) {
488 IMAGE_LOGE("AstcSoftwareEncodeCore failed");
489 return ERROR;
490 }
491 return SUCCESS;
492 }
493
494 static bool AstcEncProcess(TextureEncodeOptions ¶m, uint8_t *pixmapIn, uint8_t *astcBuffer)
495 {
496 #ifdef ENABLE_ASTC_ENCODE_BASED_GPU
497 bool openClEnc = param.width_ >= WIDTH_CL_THRESHOLD && param.height_ >= HEIGHT_CL_THRESHOLD &&
498 param.privateProfile_ == QualityProfile::HIGH_SPEED_PROFILE;
499 bool enableClEnc = openClEnc && ImageSystemProperties::GetAstcHardWareEncodeEnabled() &&
500 (param.blockX_ == DEFAULT_DIM) && (param.blockY_ == DEFAULT_DIM); // HardWare only support 4x4 now
501 if (enableClEnc) {
502 IMAGE_LOGI("astc hardware encode begin");
503 std::string clBinPath = "/sys_prod/etc/graphic/AstcEncShader_ALN-AL00.bin";
504 param.hardwareFlag = CheckClBinIsExist(clBinPath) &&
505 AstcCodec::TryAstcEncBasedOnCl(param, pixmapIn, astcBuffer, clBinPath);
506 }
507 #endif
508 if (!param.hardwareFlag) {
509 if (!AstcCodec::AstcSoftwareEncodeCore(param, pixmapIn, astcBuffer)) {
510 IMAGE_LOGE("AstcSoftwareEncodeCore failed");
511 return false;
512 }
513 IMAGE_LOGD("astc software encode success!");
514 }
515 return true;
516 }
517
518 uint32_t AstcCodec::ASTCEncode()
519 {
520 ImageInfo imageInfo;
521 astcPixelMap_->GetImageInfo(imageInfo);
522 TextureEncodeOptions param;
523 uint8_t *pixmapIn = static_cast<uint8_t *>(astcPixelMap_->GetWritablePixels());
524 int32_t stride = astcPixelMap_->GetRowStride() >> RGBA_BYTES_PIXEL_LOG2;
525 if (!InitAstcEncPara(param, imageInfo.size.width, imageInfo.size.height, stride, astcOpts_)) {
526 IMAGE_LOGE("InitAstcEncPara failed");
527 return ERROR;
528 }
529 AstcExtendInfo extendInfo = {0};
530 if (!InitAstcExtendInfo(extendInfo)) {
531 IMAGE_LOGE("InitAstcExtendInfo failed");
532 return ERROR;
533 }
534 uint32_t packSize = static_cast<uint32_t>(param.astcBytes) +
535 extendInfo.extendBufferSumBytes + ASTC_EXTEND_INFO_SIZE_DEFINITION_LENGTH;
536 uint8_t *astcBuffer = static_cast<uint8_t *>(malloc(packSize));
537 if (astcBuffer == nullptr) {
538 IMAGE_LOGE("astc astcBuffer malloc failed!");
539 ReleaseExtendInfoMemory(extendInfo);
540 return ERROR;
541 }
542 if (!AstcEncProcess(param, pixmapIn, astcBuffer)) {
543 IMAGE_LOGE("astc AstcEncProcess failed!");
544 ReleaseExtendInfoMemory(extendInfo);
545 free(astcBuffer);
546 return ERROR;
547 }
548 #ifdef SUT_ENCODE_ENABLE
549 if (!TryTextureSuperCompress(param, astcBuffer)) {
550 IMAGE_LOGE("astc TryTextureSuperCompress failed!");
551 ReleaseExtendInfoMemory(extendInfo);
552 free(astcBuffer);
553 return ERROR;
554 }
555 #endif
556 if (!param.outIsSut) { // only support astc for color space
557 WriteAstcExtendInfo(astcBuffer, static_cast<uint32_t>(param.astcBytes), extendInfo);
558 } else {
559 packSize = static_cast<uint32_t>(param.sutBytes);
560 }
561 ReleaseExtendInfoMemory(extendInfo);
562 astcOutput_->Write(astcBuffer, packSize);
563 free(astcBuffer);
564 IMAGE_LOGD("astcenc end: %{public}dx%{public}d, GpuFlag %{public}d, sut%{public}d",
565 imageInfo.size.width, imageInfo.size.height, param.hardwareFlag, param.sutProfile);
566 astcOutput_->SetOffset(packSize);
567 return SUCCESS;
568 }
569
570 bool AllocMemForExtInfo(AstcExtendInfo &extendInfo, uint8_t idx)
571 {
572 AstcExtendInfoType type = static_cast<AstcExtendInfoType>(idx);
573 switch (type) {
574 case AstcExtendInfoType::COLOR_SPACE:
575 extendInfo.extendInfoLength[idx] = ASTC_EXTEND_INFO_COLOR_SPACE_VALUE_LENGTH;
576 extendInfo.extendBufferSumBytes += ASTC_EXTEND_INFO_TYPE_LENGTH +
577 ASTC_EXTEND_INFO_LENGTH_LENGTH + ASTC_EXTEND_INFO_COLOR_SPACE_VALUE_LENGTH;
578 extendInfo.extendInfoValue[idx] = static_cast<uint8_t*>(malloc(extendInfo.extendInfoLength[idx]));
579 if (extendInfo.extendInfoValue[idx] == nullptr) {
580 IMAGE_LOGE("[AstcCodec] SetColorSpaceInfo malloc failed!");
581 return false;
582 }
583 break;
584 default:
585 return false;
586 }
587 return true;
588 }
589
590 bool AstcCodec::InitAstcExtendInfo(AstcExtendInfo &extendInfo)
591 {
592 if (memset_s(&extendInfo, sizeof(AstcExtendInfo), 0, sizeof(AstcExtendInfo)) != 0) {
593 return false;
594 }
595 extendInfo.extendNums = ASTC_EXTEND_INFO_TLV_NUM;
596 extendInfo.extendBufferSumBytes = 0;
597 for (uint8_t idx = 0; idx < extendInfo.extendNums; idx++) {
598 if (!AllocMemForExtInfo(extendInfo, idx)) {
599 ReleaseExtendInfoMemory(extendInfo);
600 IMAGE_LOGE("[AstcCodec] AllocMemForExtInfo failed!");
601 return false;
602 }
603 }
604 return true;
605 }
606
607 void AstcCodec::ReleaseExtendInfoMemory(AstcExtendInfo &extendInfo)
608 {
609 for (uint8_t idx = 0; idx < extendInfo.extendNums; idx++) {
610 if (extendInfo.extendInfoValue[idx] != nullptr) {
611 free(extendInfo.extendInfoValue[idx]);
612 extendInfo.extendInfoValue[idx] = nullptr;
613 }
614 }
615 }
616
617 static void FillDataSize(uint8_t *buf, uint32_t bytes)
618 {
619 *buf++ = (bytes) & MASKBITS_FOR_8BITS;
620 *buf++ = (bytes >> UINT32_1TH_BYTES) & MASKBITS_FOR_8BITS;
621 *buf++ = (bytes >> UINT32_2TH_BYTES) & MASKBITS_FOR_8BITS;
622 *buf++ = (bytes >> UINT32_3TH_BYTES) & MASKBITS_FOR_8BITS;
623 }
624
625 void AstcCodec::WriteAstcExtendInfo(uint8_t *buffer, uint32_t offset, AstcExtendInfo &extendInfo)
626 {
627 uint8_t* offsetBuffer = buffer + offset;
628 FillDataSize(offsetBuffer, extendInfo.extendBufferSumBytes);
629 offsetBuffer += ASTC_EXTEND_INFO_SIZE_DEFINITION_LENGTH;
630 #ifdef IMAGE_COLORSPACE_FLAG
631 ColorManager::ColorSpace colorspace = astcPixelMap_->InnerGetGrColorSpace();
632 ColorManager::ColorSpaceName csName = colorspace.GetColorSpaceName();
633 #endif
634 for (uint8_t idx = 0; idx < extendInfo.extendNums; idx++) {
635 *offsetBuffer++ = idx;
636 FillDataSize(offsetBuffer, extendInfo.extendInfoLength[idx]);
637 offsetBuffer += ASTC_EXTEND_INFO_LENGTH_LENGTH;
638 AstcExtendInfoType type = static_cast<AstcExtendInfoType>(idx);
639 switch (type) {
640 case AstcExtendInfoType::COLOR_SPACE:
641 #ifdef IMAGE_COLORSPACE_FLAG
642 *offsetBuffer = static_cast<uint8_t>(csName);
643 #else
644 *offsetBuffer = 0;
645 #endif
646 break;
647 default:
648 return;
649 }
650 }
651 }
652 } // namespace ImagePlugin
653 } // namespace OHOS
654