• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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