1 /*
2 * Copyright (C) 2024 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 <message_parcel.h>
17 #include <securec.h>
18 #include <surface_buffer.h>
19 #include <sys/mman.h>
20
21 #include "media_errors.h"
22 #include "pixel_map.h"
23 #include "rs_profiler.h"
24 #include "rs_profiler_cache.h"
25 #include "rs_profiler_utils.h"
26 #include "rs_profiler_log.h"
27 #include "rs_profiler_pixelmap.h"
28
29 #include "transaction/rs_marshalling_helper.h"
30 #include "platform/common/rs_system_properties.h"
31
32 #ifdef ROSEN_OHOS
33 #include "lz4.h"
34 #endif
35
36 #include "image_packer.h"
37 #include "image_source.h"
38 #define ALPHA_OFFSET 4
39 #define SIZE_OF_PIXEL 4
40 #define RGB_OFFSET 3
41
42 namespace OHOS::Rosen {
43
ImageProperties(PixelMap & map)44 ImageProperties::ImageProperties(PixelMap& map)
45 : format(map.GetPixelFormat()), width(map.GetWidth()), height(map.GetHeight()),
46 stride(map.GetRowStride())
47 {}
48
IsSharedMemory(const PixelMap & map)49 bool PixelMapStorage::IsSharedMemory(const PixelMap& map)
50 {
51 return IsSharedMemory(const_cast<PixelMap&>(map).GetAllocatorType());
52 }
53
IsSharedMemory(const PixelMemInfo & info)54 bool PixelMapStorage::IsSharedMemory(const PixelMemInfo& info)
55 {
56 return IsSharedMemory(info.allocatorType);
57 }
58
IsSharedMemory(AllocatorType type)59 bool PixelMapStorage::IsSharedMemory(AllocatorType type)
60 {
61 return type == AllocatorType::SHARE_MEM_ALLOC;
62 }
63
IsDmaMemory(const PixelMap & map)64 bool PixelMapStorage::IsDmaMemory(const PixelMap& map)
65 {
66 return IsDmaMemory(const_cast<PixelMap&>(map).GetAllocatorType());
67 }
68
IsDmaMemory(const PixelMemInfo & info)69 bool PixelMapStorage::IsDmaMemory(const PixelMemInfo& info)
70 {
71 return IsDmaMemory(info.allocatorType);
72 }
73
IsDmaMemory(AllocatorType type)74 bool PixelMapStorage::IsDmaMemory(AllocatorType type)
75 {
76 return type == AllocatorType::DMA_ALLOC;
77 }
78
Fits(size_t size)79 bool PixelMapStorage::Fits(size_t size)
80 {
81 constexpr size_t maxConsumption = 1024u * 1024u * 1024u;
82 return (ImageCache::Consumption() + size) <= maxConsumption;
83 }
84
Push(uint64_t id,PixelMap & map)85 bool PixelMapStorage::Push(uint64_t id, PixelMap& map)
86 {
87 if (!Fits(static_cast<size_t>(const_cast<PixelMap&>(map).GetCapacity()))) {
88 return false;
89 }
90
91 if (IsDmaMemory(map)) {
92 PushDmaMemory(id, map);
93 } else if (IsSharedMemory(map)) {
94 PushSharedMemory(id, map);
95 }
96 return true;
97 }
98
Pull(uint64_t id,const ImageInfo & info,PixelMemInfo & memory,size_t & skipBytes)99 bool PixelMapStorage::Pull(uint64_t id, const ImageInfo& info, PixelMemInfo& memory, size_t& skipBytes)
100 {
101 skipBytes = 0u;
102 if (IsSharedMemory(memory)) {
103 return PullSharedMemory(id, info, memory, skipBytes);
104 } else if (IsDmaMemory(memory)) {
105 return PullDmaMemory(id, info, memory, skipBytes);
106 }
107 return false;
108 }
109
Push(uint64_t id,const ImageInfo & info,const PixelMemInfo & memory,size_t skipBytes)110 bool PixelMapStorage::Push(uint64_t id, const ImageInfo& info, const PixelMemInfo& memory, size_t skipBytes)
111 {
112 if (!Fits(static_cast<size_t>(memory.bufferSize))) {
113 return false;
114 }
115
116 if (IsSharedMemory(memory)) {
117 PushSharedMemory(id, info, memory, skipBytes);
118 } else if (IsDmaMemory(memory)) {
119 PushDmaMemory(id, info, memory, skipBytes);
120 }
121 return true;
122 }
123
PullSharedMemory(uint64_t id,const ImageInfo & info,PixelMemInfo & memory,size_t & skipBytes)124 bool PixelMapStorage::PullSharedMemory(uint64_t id, const ImageInfo& info, PixelMemInfo& memory, size_t& skipBytes)
125 {
126 skipBytes = 0u;
127 if (!ValidateBufferSize(memory)) {
128 return false;
129 }
130
131 auto image = ImageCache::Get(id);
132 if (!image) {
133 return false;
134 }
135
136 memory.allocatorType = AllocatorType::HEAP_ALLOC;
137 memory.base = reinterpret_cast<uint8_t*>(malloc(memory.bufferSize));
138 if (!memory.base) {
139 return false;
140 }
141
142 if (!CopyImageData(image, memory.base, memory.bufferSize)) {
143 free(memory.base);
144 memory.base = nullptr;
145 return false;
146 }
147
148 memory.context = nullptr;
149 skipBytes = image->parcelSkipBytes;
150 return true;
151 }
152
PushSharedMemory(uint64_t id,const ImageInfo & info,const PixelMemInfo & memory,size_t skipBytes)153 void PixelMapStorage::PushSharedMemory(uint64_t id, const ImageInfo& info, const PixelMemInfo& memory, size_t skipBytes)
154 {
155 PushImage(id, GenerateImageData(info, memory), skipBytes);
156 }
157
PushSharedMemory(uint64_t id,PixelMap & map)158 void PixelMapStorage::PushSharedMemory(uint64_t id, PixelMap& map)
159 {
160 if (!map.GetFd()) {
161 return;
162 }
163
164 constexpr size_t skipBytes = 24u;
165 const auto size = static_cast<size_t>(const_cast<PixelMap&>(map).GetByteCount());
166 const ImageProperties properties(map);
167 if (auto image = MapImage(*reinterpret_cast<const int32_t*>(map.GetFd()), size, PROT_READ)) {
168 PushImage(id, GenerateImageData(image, size, map), skipBytes, nullptr, &properties);
169 UnmapImage(image, size);
170 }
171 }
172
PullDmaMemory(uint64_t id,const ImageInfo & info,PixelMemInfo & memory,size_t & skipBytes)173 bool PixelMapStorage::PullDmaMemory(uint64_t id, const ImageInfo& info, PixelMemInfo& memory, size_t& skipBytes)
174 {
175 skipBytes = 0u;
176 if (!ValidateBufferSize(memory)) {
177 return false;
178 }
179
180 auto image = ImageCache::Get(id);
181 if (!image) {
182 return false;
183 }
184
185 auto surfaceBuffer = SurfaceBuffer::Create();
186 if (!surfaceBuffer) {
187 return false;
188 }
189
190 const BufferRequestConfig config = { .width = image->dmaWidth,
191 .height = image->dmaHeight,
192 .strideAlignment = image->dmaStride,
193 .format = image->dmaFormat,
194 .usage = image->dmaUsage };
195 surfaceBuffer->Alloc(config);
196
197 memory.base = static_cast<uint8_t*>(surfaceBuffer->GetVirAddr());
198 if (!CopyImageData(image, memory.base, image->dmaSize)) {
199 return false;
200 }
201
202 memory.context = IncrementSurfaceBufferReference(surfaceBuffer);
203 skipBytes = image->parcelSkipBytes;
204 return true;
205 }
206
PushDmaMemory(uint64_t id,const ImageInfo & info,const PixelMemInfo & memory,size_t skipBytes)207 void PixelMapStorage::PushDmaMemory(uint64_t id, const ImageInfo& info, const PixelMemInfo& memory, size_t skipBytes)
208 {
209 auto surfaceBuffer = reinterpret_cast<SurfaceBuffer*>(memory.context);
210 auto buffer = surfaceBuffer ? surfaceBuffer->GetBufferHandle() : nullptr;
211 if (buffer) {
212 const auto pixels = GenerateImageData(memory.base, buffer->size, memory.isAstc, GetBytesPerPixel(info));
213 PushImage(id, pixels, skipBytes, buffer);
214 }
215 }
216
PushDmaMemory(uint64_t id,PixelMap & map)217 void PixelMapStorage::PushDmaMemory(uint64_t id, PixelMap& map)
218 {
219 const auto surfaceBuffer = reinterpret_cast<SurfaceBuffer*>(map.GetFd());
220 const auto buffer = surfaceBuffer ? surfaceBuffer->GetBufferHandle() : nullptr;
221 if (!buffer) {
222 return;
223 }
224 const ImageProperties properties(map);
225 const auto pixels =
226 GenerateImageData(reinterpret_cast<const uint8_t*>(surfaceBuffer->GetVirAddr()), buffer->size, map);
227 MessageParcel parcel;
228 surfaceBuffer->WriteToMessageParcel(parcel);
229 PushImage(id, pixels, parcel.GetReadableBytes(), buffer, &properties);
230 }
231
EncodeSeqLZ4(const ImageData & source,ImageData & dst)232 int32_t PixelMapStorage::EncodeSeqLZ4(const ImageData& source, ImageData& dst)
233 {
234 #ifdef ROSEN_OHOS
235 int32_t dstCap = LZ4_compressBound(source.size());
236 ImageData buf;
237 buf.reserve(dstCap);
238
239 auto start = reinterpret_cast<const char*>(source.data());
240 int32_t encodedSize = LZ4_compress_default(start, reinterpret_cast<char*>(buf.data()), source.size(), dstCap);
241 if (encodedSize < 0) {
242 HRPE("Error when encoding lz4");
243 return -1;
244 }
245
246 dst.insert(dst.end(), buf.data(), buf.data() + encodedSize);
247 return encodedSize;
248 #else
249 HRPD("lz4 encoding is not supported on this platform");
250 return -1;
251 #endif
252 }
253
EncodeJpeg(const ImageData & source,ImageData & dst,const ImageProperties & properties)254 int32_t PixelMapStorage::EncodeJpeg(const ImageData& source, ImageData& dst, const ImageProperties& properties)
255 {
256 Media::InitializationOptions opts = { .size = { .width = properties.width, .height = properties.height },
257 .srcPixelFormat = properties.format,
258 .pixelFormat = properties.format,
259 .srcRowStride = properties.stride,
260 .alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE };
261 auto sourceRgb = Media::PixelMap::Create(reinterpret_cast<const uint32_t*>(source.data()), source.size(), opts);
262 if (!sourceRgb) {
263 HRPE("Failed to create source to encode to rgb");
264 return -1;
265 }
266 uint32_t err = 0;
267 Media::ImagePacker imagePacker;
268 Media::PackOption option;
269 option.format = "image/jpeg";
270 ImageData dstRgb;
271 dstRgb.reserve(source.size());
272 err = imagePacker.StartPacking(static_cast<uint8_t*>(dstRgb.data()), source.size(), option);
273 if (err != 0) {
274 HRPE("Failed to start packing to jpeg, errcode %{public}u", err);
275 return -1;
276 }
277 err = imagePacker.AddImage(*sourceRgb);
278 if (err != 0) {
279 HRPE("Failed to AddImage, errcode %{public}u", err);
280 return -1;
281 }
282 int64_t encodedSize = 0;
283 err = imagePacker.FinalizePacking(encodedSize);
284 if (err != 0) {
285 HRPE("Failed to FinalizePacking, errcode %{public}u", err);
286 return -1;
287 }
288 dst.insert(dst.end(), dstRgb.data(), dstRgb.data() + encodedSize);
289 return encodedSize;
290 }
291
ExtractAlpha(const ImageData & image,ImageData & alpha,const ImageProperties & properties)292 void PixelMapStorage::ExtractAlpha(const ImageData& image, ImageData& alpha, const ImageProperties& properties)
293 {
294 alpha.reserve(image.size() / ALPHA_OFFSET);
295 for (int32_t row = 0, rStart = 0; row < properties.height; ++row, rStart += properties.stride) {
296 for (int32_t pixIdx = 0, alphaIdx = rStart + RGB_OFFSET;
297 pixIdx < properties.width; ++pixIdx, alphaIdx += ALPHA_OFFSET) {
298 alpha.emplace_back(image[alphaIdx]);
299 }
300 }
301 }
302
PushImage(uint64_t id,const ImageData & data,size_t skipBytes,BufferHandle * buffer,const ImageProperties * properties)303 void PixelMapStorage::PushImage(
304 uint64_t id, const ImageData& data, size_t skipBytes, BufferHandle* buffer, const ImageProperties* properties)
305 {
306 if (data.empty()) {
307 return;
308 }
309
310 if (buffer && ((buffer->width == 0) || (buffer->height == 0))) {
311 return;
312 }
313
314 Image image;
315 image.parcelSkipBytes = skipBytes;
316 if (buffer) {
317 image.dmaSize = static_cast<size_t>(buffer->size);
318 image.dmaWidth = buffer->width;
319 image.dmaHeight = buffer->height;
320 image.dmaStride = buffer->stride;
321 image.dmaFormat = buffer->format;
322 image.dmaUsage = buffer->usage;
323 }
324
325 EncodedType encodedType = EncodedType::NONE;
326 if (RSProfiler::IsWriteEmulationMode() && !RSProfiler::IsBetaRecordEnabled()) {
327 // COMPRESS WITH LZ4 OR JPEG
328 encodedType = TryEncodeTexture(properties, data, image);
329 }
330 if (encodedType == EncodedType::NONE) {
331 // NO COMPRESION
332 image.data = data;
333 }
334
335 ImageCache::Add(id, std::move(image));
336 }
337
TryEncodeTexture(const ImageProperties * properties,const ImageData & data,Image & image)338 EncodedType PixelMapStorage::TryEncodeTexture(const ImageProperties* properties, const ImageData& data, Image& image)
339 {
340 EncodedType encodedType = EncodedType::NONE;
341
342 image.data.resize(sizeof(TextureHeader));
343 if (properties &&
344 (properties->format == Media::PixelFormat::RGBA_8888 || properties->format == Media::PixelFormat::BGRA_8888) &&
345 static_cast<int32_t>(data.size()) == properties->stride * properties->height) {
346 int32_t rgbEncodedSize = EncodeJpeg(data, image.data, *properties);
347 if (rgbEncodedSize != -1) {
348 ImageData alpha;
349 ExtractAlpha(data, alpha, *properties);
350 int32_t alphaEncodedSize = EncodeSeqLZ4(alpha, image.data);
351 if (alphaEncodedSize != -1) {
352 encodedType = EncodedType::JPEG;
353 TextureHeader* header = reinterpret_cast<TextureHeader*>(image.data.data());
354 header->magicNumber = 'JPEG';
355 header->properties = *properties;
356 header->totalOriginalSize = data.size();
357 header->rgbEncodedSize = rgbEncodedSize;
358 header->alphaOriginalSize = alpha.size();
359 header->alphaEncodedSize = alphaEncodedSize;
360 }
361 }
362 }
363 if (encodedType == EncodedType::NONE) {
364 int32_t encodedSize = EncodeSeqLZ4(data, image.data);
365 if (encodedSize != -1) {
366 encodedType = EncodedType::XLZ4;
367 TextureHeader* header = reinterpret_cast<TextureHeader*>(image.data.data());
368 header->magicNumber = 'XLZ4';
369 header->totalOriginalSize = data.size();
370 }
371 }
372 return encodedType;
373 }
374
ValidateBufferSize(const PixelMemInfo & memory)375 bool PixelMapStorage::ValidateBufferSize(const PixelMemInfo& memory)
376 {
377 return (memory.bufferSize > 0) && (static_cast<size_t>(memory.bufferSize) <= Image::maxSize);
378 }
379
GetBytesPerPixel(const ImageInfo & info)380 uint32_t PixelMapStorage::GetBytesPerPixel(const ImageInfo& info)
381 {
382 const auto rowPitch = PixelMap::GetRGBxRowDataSize(info);
383 return (rowPitch > 0) ? static_cast<uint32_t>(rowPitch / info.size.width) : 0u;
384 }
385
MapImage(int32_t file,size_t size,int32_t flags)386 uint8_t* PixelMapStorage::MapImage(int32_t file, size_t size, int32_t flags)
387 {
388 auto image = ::mmap(nullptr, size, flags, MAP_SHARED, file, 0);
389 return (image != MAP_FAILED) ? reinterpret_cast<uint8_t*>(image) : nullptr; // NOLINT
390 }
391
UnmapImage(void * image,size_t size)392 void PixelMapStorage::UnmapImage(void* image, size_t size)
393 {
394 if (IsDataValid(image, size)) {
395 ::munmap(image, size);
396 }
397 }
398
IncrementSurfaceBufferReference(sptr<SurfaceBuffer> & buffer)399 SurfaceBuffer* PixelMapStorage::IncrementSurfaceBufferReference(sptr<SurfaceBuffer>& buffer)
400 {
401 if (auto object = buffer.GetRefPtr()) {
402 object->IncStrongRef(object);
403 return object;
404 }
405 return nullptr;
406 }
407
IsDataValid(const void * data,size_t size)408 bool PixelMapStorage::IsDataValid(const void* data, size_t size)
409 {
410 return data && (size > 0);
411 }
412
CopyImageData(const uint8_t * srcImage,size_t srcSize,uint8_t * dstImage,size_t dstSize)413 bool PixelMapStorage::CopyImageData(const uint8_t* srcImage, size_t srcSize, uint8_t* dstImage, size_t dstSize)
414 {
415 if (!srcImage || !dstImage || (srcSize == 0) || (dstSize == 0) || (srcSize > dstSize)) {
416 return false;
417 }
418
419 if (dstSize == srcSize) {
420 return Utils::Move(dstImage, dstSize, srcImage, srcSize);
421 }
422
423 for (size_t offset = 0; offset < dstSize;) {
424 const size_t size = std::min(dstSize - offset, srcSize);
425 if (!Utils::Move(dstImage + offset, size, srcImage, size)) {
426 return false;
427 }
428 offset += size;
429 }
430
431 return true;
432 }
433
CopyImageData(const ImageData & data,uint8_t * dstImage,size_t dstSize)434 bool PixelMapStorage::CopyImageData(const ImageData& data, uint8_t* dstImage, size_t dstSize)
435 {
436 return CopyImageData(data.data(), data.size(), dstImage, dstSize);
437 }
438
ReplaceAlpha(ImageData & image,ImageData & alpha,const ImageProperties & properties)439 void PixelMapStorage::ReplaceAlpha(ImageData& image, ImageData& alpha, const ImageProperties& properties)
440 {
441 int32_t i = 0;
442 for (int32_t row = 0, rStart = 0; row < properties.height; ++row, rStart += properties.stride) {
443 for (int32_t pixIdx = 0, alphaIdx = rStart + RGB_OFFSET; pixIdx < properties.width;
444 ++pixIdx, alphaIdx += ALPHA_OFFSET) {
445 image[alphaIdx] = alpha[i++];
446 }
447 }
448 }
449
MakeStride(ImageData & noPadding,ImageData & dst,const ImageProperties & properties,int32_t pixelBytes)450 int32_t PixelMapStorage::MakeStride(
451 ImageData& noPadding, ImageData& dst, const ImageProperties& properties, int32_t pixelBytes)
452 {
453 int32_t padding = properties.stride - properties.width * pixelBytes;
454 for (int32_t row = 0; row < properties.height; row++) {
455 int32_t rowStart = properties.width * pixelBytes * row;
456 int32_t nextRowStart = properties.width * pixelBytes + rowStart;
457 dst.insert(dst.end(), noPadding.begin() + rowStart, noPadding.begin() + nextRowStart);
458 dst.insert(dst.end(), padding, 0);
459 }
460
461 return dst.size();
462 }
463
DecodeSeqLZ4(const char * source,ImageData & dst,int32_t sourceSize,int32_t originalSize)464 int32_t PixelMapStorage::DecodeSeqLZ4(const char* source, ImageData& dst, int32_t sourceSize, int32_t originalSize)
465 {
466 #ifdef ROSEN_OHOS
467 dst.resize(originalSize);
468 int cnt = LZ4_decompress_safe_partial(
469 source, reinterpret_cast<char*>(dst.data()), sourceSize, originalSize, originalSize);
470 return cnt;
471 #else
472 HRPE("lz4 encoding is not supported on this platform");
473 return -1;
474 #endif
475 }
476
DecodeJpeg(const char * source,ImageData & dst,int32_t sourceSize,const ImageProperties & properties)477 int32_t PixelMapStorage::DecodeJpeg(
478 const char* source, ImageData& dst, int32_t sourceSize, const ImageProperties& properties)
479 {
480 Media::SourceOptions opts = { .formatHint = "image/jpeg",
481 .pixelFormat = properties.format,
482 .size = { .width = properties.width, .height = properties.height } };
483 uint32_t err;
484 auto src = Media::ImageSource::CreateImageSource(reinterpret_cast<const uint8_t*>(source), sourceSize, opts, err);
485 if (!src || err != 0) {
486 HRPE("Error when creating source, errcode %{public}u", err);
487 return -1;
488 }
489 Media::DecodeOptions dopts;
490 auto pmap = src->CreatePixelMap(dopts, err);
491 if (!pmap || err != 0) {
492 HRPE("Error when creating pixelmap, errcode %{public}u", err);
493 return -1;
494 }
495 ImageData noPadding;
496 noPadding.reserve(properties.width * properties.height * SIZE_OF_PIXEL);
497 err = pmap->ReadPixels(pmap->GetByteCount(), noPadding.data());
498 if (err != 0) {
499 HRPE("Error when reading pixels, errcode %{public}u", err);
500 return -1;
501 }
502
503 return MakeStride(noPadding, dst, properties, ALPHA_OFFSET);
504 }
505
CopyImageData(Image * image,uint8_t * dstImage,size_t dstSize)506 bool PixelMapStorage::CopyImageData(Image* image, uint8_t* dstImage, size_t dstSize)
507 {
508 if (!image) {
509 return false;
510 }
511
512 TextureHeader* header = reinterpret_cast<TextureHeader*>(image->data.data());
513 const char* srcStart = reinterpret_cast<const char*>(image->data.data()) + sizeof(TextureHeader);
514 ImageData result;
515
516 if (header->magicNumber == 'JPEG' && image->data.size() >= sizeof(TextureHeader)) {
517 int32_t decodedTotalBytes = DecodeJpeg(srcStart, result, header->rgbEncodedSize, header->properties);
518 if (decodedTotalBytes == header->totalOriginalSize) {
519 ImageData alpha;
520 const char* alphaStart = srcStart + header->rgbEncodedSize;
521 int32_t decodedAlphaBytes =
522 DecodeSeqLZ4(alphaStart, alpha, header->alphaEncodedSize, header->alphaOriginalSize);
523 if (decodedAlphaBytes == header->alphaOriginalSize) {
524 ReplaceAlpha(result, alpha, header->properties);
525 image->data.clear();
526 image->data.insert(image->data.end(), result.begin(), result.end());
527 } else {
528 HRPE("Error when decoding alpha got %{public}d bytes, expected %{public}d bytes", decodedAlphaBytes,
529 header->alphaOriginalSize);
530 }
531 } else {
532 HRPE("Error when decoding rgb got %{public}d bytes, expected %{public}d bytes", decodedTotalBytes,
533 header->totalOriginalSize);
534 }
535 } else if (header->magicNumber == 'XLZ4' && image->data.size() >= sizeof(TextureHeader)) {
536 int32_t sourceSize = image->data.size() - sizeof(TextureHeader);
537 int32_t decodedTotalBytes = DecodeSeqLZ4(srcStart, result, sourceSize, header->totalOriginalSize);
538 if (decodedTotalBytes == header->totalOriginalSize) {
539 image->data.clear();
540 image->data.insert(image->data.end(), result.begin(), result.end());
541 } else {
542 HRPE("Error when decoding lz4 got %{public}d bytes, expected %{public}d bytes", decodedTotalBytes,
543 header->totalOriginalSize);
544 }
545 } else {
546 // assume image was not encoded, do nothing
547 }
548
549 return CopyImageData(image->data, dstImage, dstSize);
550 }
551
GenerateRawCopy(const uint8_t * data,size_t size)552 ImageData PixelMapStorage::GenerateRawCopy(const uint8_t* data, size_t size)
553 {
554 ImageData out;
555 if (IsDataValid(data, size)) {
556 out.insert(out.end(), data, data + size);
557 }
558 return out;
559 }
560
GenerateMiniatureAstc(const uint8_t * data,size_t size)561 ImageData PixelMapStorage::GenerateMiniatureAstc(const uint8_t* data, size_t size)
562 {
563 constexpr uint32_t astcBytesPerPixel = 16u;
564 return GenerateRawCopy(data, astcBytesPerPixel);
565 }
566
GenerateMiniature(const uint8_t * data,size_t size,uint32_t pixelBytes)567 ImageData PixelMapStorage::GenerateMiniature(const uint8_t* data, size_t size, uint32_t pixelBytes)
568 {
569 if (!IsDataValid(data, size)) {
570 return {};
571 }
572
573 constexpr uint32_t rgbaBytesPerPixel = 4u;
574 constexpr uint32_t pixelBytesThreshold = 256u; // in case the pixelBytes field in the map has invalid value
575 const uint32_t bytesPerPixel =
576 ((pixelBytes > 0) && (pixelBytes < pixelBytesThreshold)) ? pixelBytes : rgbaBytesPerPixel;
577
578 const auto pixelCount = size / bytesPerPixel;
579
580 std::vector<uint64_t> averageValue(bytesPerPixel, 0);
581 constexpr uint32_t sampleCount = 100u;
582 for (uint32_t sample = 0; sample < sampleCount; sample++) {
583 for (uint32_t channel = 0; channel < bytesPerPixel; channel++) {
584 const size_t dataIdx = (sample * pixelCount / sampleCount) * bytesPerPixel + channel;
585 averageValue[channel] += (dataIdx < size) ? data[dataIdx] : 0;
586 }
587 }
588
589 ImageData out(bytesPerPixel, 0);
590 for (uint32_t i = 0; i < bytesPerPixel; i++) {
591 out[i] = static_cast<uint8_t>(averageValue[i] / sampleCount);
592 }
593 return out;
594 }
595
GenerateImageData(const uint8_t * data,size_t size,const PixelMap & map)596 ImageData PixelMapStorage::GenerateImageData(const uint8_t* data, size_t size, const PixelMap& map)
597 {
598 const auto bytesPerPixel = static_cast<uint32_t>(const_cast<PixelMap&>(map).GetPixelBytes());
599 return GenerateImageData(data, size, const_cast<PixelMap&>(map).IsAstc(), bytesPerPixel);
600 }
601
GenerateImageData(const ImageInfo & info,const PixelMemInfo & memory)602 ImageData PixelMapStorage::GenerateImageData(const ImageInfo& info, const PixelMemInfo& memory)
603 {
604 return GenerateImageData(
605 memory.base, static_cast<size_t>(memory.bufferSize), memory.isAstc, GetBytesPerPixel(info));
606 }
607
GenerateImageData(const uint8_t * data,size_t size,bool isAstc,uint32_t pixelBytes)608 ImageData PixelMapStorage::GenerateImageData(const uint8_t* data, size_t size, bool isAstc, uint32_t pixelBytes)
609 {
610 if (!RSProfiler::IsBetaRecordEnabled()) {
611 return GenerateRawCopy(data, size);
612 }
613
614 return isAstc ? GenerateMiniatureAstc(data, size) : GenerateMiniature(data, size, pixelBytes);
615 }
616
617 // Profiler
618
SkipPixelMap(Parcel & parcel)619 bool RSProfiler::SkipPixelMap(Parcel& parcel)
620 {
621 if (IsEnabled() && IsWriteMode()) {
622 std::shared_ptr<Media::PixelMap> pixelMap;
623 RSMarshallingHelper::Unmarshalling(parcel, pixelMap);
624 return true;
625 }
626 return false;
627 }
628
MarshalPixelMap(Parcel & parcel,const std::shared_ptr<Media::PixelMap> & map)629 bool RSProfiler::MarshalPixelMap(Parcel& parcel, const std::shared_ptr<Media::PixelMap>& map)
630 {
631 if (!map) {
632 return false;
633 }
634
635 const bool profilerEnabled = RSSystemProperties::GetProfilerEnabled();
636 if (!parcel.WriteBool(profilerEnabled)) {
637 HRPE("MarshalPixelMap: Unable to write profilerEnabled");
638 return false;
639 }
640
641 if (!profilerEnabled) {
642 return map->Marshalling(parcel);
643 }
644
645 const uint64_t id = ImageCache::New();
646 if (!parcel.WriteUint64(id) || !map->Marshalling(parcel)) {
647 HRPE("MarshalPixelMap: Unable to write id");
648 return false;
649 }
650
651 if (IsSharedMemoryEnabled()) {
652 return true;
653 }
654
655 if (!IsRecordAbortRequested() && (IsWriteMode() || IsWriteEmulationMode())) {
656 if (!PixelMapStorage::Push(id, *map)) {
657 RequestRecordAbort();
658 }
659 }
660 return true;
661 }
662
UnmarshalPixelMap(Parcel & parcel,std::function<int (Parcel & parcel,std::function<int (Parcel &)> readFdDefaultFunc)> readSafeFdFunc)663 Media::PixelMap* RSProfiler::UnmarshalPixelMap(Parcel& parcel,
664 std::function<int(Parcel& parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc)
665 {
666 bool profilerEnabled = false;
667 if (!parcel.ReadBool(profilerEnabled)) {
668 HRPE("UnmarshalPixelMap: Unable to read profilerEnabled");
669 return nullptr;
670 }
671
672 if (!profilerEnabled) {
673 return PixelMap::Unmarshalling(parcel, readSafeFdFunc);
674 }
675
676 const uint64_t id = parcel.ReadUint64();
677
678 if (IsRecordAbortRequested()) {
679 return PixelMap::Unmarshalling(parcel, readSafeFdFunc);
680 }
681
682 ImageInfo info;
683 PixelMemInfo memory;
684 PIXEL_MAP_ERR error;
685 auto map = PixelMap::StartUnmarshalling(parcel, info, memory, error);
686
687 if (IsReadMode() || IsReadEmulationMode()) {
688 size_t skipBytes = 0u;
689 if (PixelMapStorage::Pull(id, info, memory, skipBytes)) {
690 parcel.SkipBytes(skipBytes);
691 return PixelMap::FinishUnmarshalling(map, parcel, info, memory, error);
692 }
693 }
694
695 const auto parcelPosition = parcel.GetReadPosition();
696 if (map && !PixelMap::ReadMemInfoFromParcel(parcel, memory, error, readSafeFdFunc)) {
697 delete map;
698 return nullptr;
699 }
700
701 if (IsWriteMode() || IsWriteEmulationMode()) {
702 if (!PixelMapStorage::Push(id, info, memory, parcel.GetReadPosition() - parcelPosition)) {
703 RequestRecordAbort();
704 }
705 }
706 return PixelMap::FinishUnmarshalling(map, parcel, info, memory, error);
707 }
708
709 } // namespace OHOS::Rosen