• 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 "pixel_map_parcel.h"
24 #include "rs_profiler.h"
25 #include "rs_profiler_cache.h"
26 #include "rs_profiler_utils.h"
27 #include "rs_profiler_log.h"
28 #include "rs_profiler_pixelmap.h"
29 #include "rs_profiler_json.h"
30 
31 #include "transaction/rs_marshalling_helper.h"
32 #include "platform/common/rs_system_properties.h"
33 
34 #ifdef ROSEN_OHOS
35 #include "lz4.h"
36 #endif
37 
38 #include "image_packer.h"
39 #include "image_source.h"
40 #define ALPHA_OFFSET 4
41 #define SIZE_OF_PIXEL 4
42 #define RGB_OFFSET 3
43 #define PIXELMAP_FLAG_PROFILER (1 << 0)
44 #define PIXELMAP_FLAG_PIXEL_CHECK (1 << 1)
45 
46 namespace OHOS::Rosen {
47 
ImageProperties(const ImageInfo & info,AllocatorType type)48 ImageProperties::ImageProperties(const ImageInfo& info, AllocatorType type)
49     : format(static_cast<int16_t>(info.pixelFormat)), allocType(static_cast<int8_t>(type)),
50       width(info.size.width), height(info.size.height),
51       stride(PixelMap::GetRGBxRowDataSize(info))
52 {}
53 
ImageProperties(PixelMap & map)54 ImageProperties::ImageProperties(PixelMap& map)
55     : format(static_cast<int16_t>(map.GetPixelFormat())), allocType(static_cast<int8_t>(map.GetAllocatorType())),
56       width(map.GetWidth()), height(map.GetHeight()), stride(map.GetRowStride())
57 {}
58 
IsSharedMemory(const PixelMap & map)59 bool PixelMapStorage::IsSharedMemory(const PixelMap& map)
60 {
61     return IsSharedMemory(const_cast<PixelMap&>(map).GetAllocatorType());
62 }
63 
IsSharedMemory(const PixelMemInfo & info)64 bool PixelMapStorage::IsSharedMemory(const PixelMemInfo& info)
65 {
66     return IsSharedMemory(info.allocatorType);
67 }
68 
IsSharedMemory(AllocatorType type)69 bool PixelMapStorage::IsSharedMemory(AllocatorType type)
70 {
71     return type == AllocatorType::SHARE_MEM_ALLOC;
72 }
73 
IsDmaMemory(const PixelMap & map)74 bool PixelMapStorage::IsDmaMemory(const PixelMap& map)
75 {
76     return IsDmaMemory(const_cast<PixelMap&>(map).GetAllocatorType());
77 }
78 
IsDmaMemory(const PixelMemInfo & info)79 bool PixelMapStorage::IsDmaMemory(const PixelMemInfo& info)
80 {
81     return IsDmaMemory(info.allocatorType);
82 }
83 
IsDmaMemory(AllocatorType type)84 bool PixelMapStorage::IsDmaMemory(AllocatorType type)
85 {
86     return type == AllocatorType::DMA_ALLOC;
87 }
88 
Fits(size_t size)89 bool PixelMapStorage::Fits(size_t size)
90 {
91     constexpr size_t maxConsumption = 1024u * 1024u * 1024u;
92     return (ImageCache::Consumption() + size) <= maxConsumption;
93 }
94 
Push(uint64_t id,PixelMap & map)95 bool PixelMapStorage::Push(uint64_t id, PixelMap& map)
96 {
97     if (!Fits(static_cast<size_t>(const_cast<PixelMap&>(map).GetCapacity()))) {
98         return false;
99     }
100 
101     if (IsDmaMemory(map)) {
102         PushDmaMemory(id, map);
103     } else if (IsSharedMemory(map)) {
104         PushSharedMemory(id, map);
105     } else {
106         PushHeapMemory(id, map);
107     }
108     return true;
109 }
110 
Pull(uint64_t id,const ImageInfo & info,PixelMemInfo & memory,size_t & skipBytes)111 bool PixelMapStorage::Pull(uint64_t id, const ImageInfo& info, PixelMemInfo& memory, size_t& skipBytes)
112 {
113     skipBytes = 0u;
114     bool retCode = false;
115     if (IsSharedMemory(memory)) {
116         retCode = PullSharedMemory(id, info, memory, skipBytes);
117     } else if (IsDmaMemory(memory)) {
118         retCode = PullDmaMemory(id, info, memory, skipBytes);
119     } else {
120         retCode = PullHeapMemory(id, info, memory, skipBytes);
121     }
122 
123     if (!retCode) {
124         retCode = DefaultHeapMemory(id, info, memory, skipBytes);
125     }
126 
127     return retCode;
128 }
129 
Push(uint64_t id,const ImageInfo & info,const PixelMemInfo & memory,size_t skipBytes)130 bool PixelMapStorage::Push(uint64_t id, const ImageInfo& info, const PixelMemInfo& memory, size_t skipBytes)
131 {
132     if (!Fits(static_cast<size_t>(memory.bufferSize))) {
133         return false;
134     }
135     auto ret = true;
136 
137     if (IsSharedMemory(memory)) {
138         ret = PushSharedMemory(id, info, memory, skipBytes);
139     } else if (IsDmaMemory(memory)) {
140         ret = PushDmaMemory(id, info, memory, skipBytes);
141     } else {
142         ret = PushHeapMemory(id, info, memory, skipBytes);
143     }
144     return ret;
145 }
146 
PullSharedMemory(uint64_t id,const ImageInfo & info,PixelMemInfo & memory,size_t & skipBytes)147 bool PixelMapStorage::PullSharedMemory(uint64_t id, const ImageInfo& info, PixelMemInfo& memory, size_t& skipBytes)
148 {
149     skipBytes = 0u;
150     if (!ValidateBufferSize(memory)) {
151         return false;
152     }
153 
154     auto image = ImageCache::Get(id);
155     if (!image) {
156         return false;
157     }
158 
159     memory.allocatorType = AllocatorType::HEAP_ALLOC;
160     memory.base = reinterpret_cast<uint8_t*>(malloc(memory.bufferSize));
161     if (!memory.base) {
162         return false;
163     }
164 
165     if (!CopyImageData(image, memory.base, memory.bufferSize)) {
166         free(memory.base);
167         memory.base = nullptr;
168         return false;
169     }
170 
171     memory.context = nullptr;
172     skipBytes = image->parcelSkipBytes;
173     return true;
174 }
175 
PushSharedMemory(uint64_t id,const ImageInfo & info,const PixelMemInfo & memory,size_t skipBytes)176 bool PixelMapStorage::PushSharedMemory(uint64_t id, const ImageInfo& info, const PixelMemInfo& memory, size_t skipBytes)
177 {
178     ImageProperties properties(info, AllocatorType::SHARE_MEM_ALLOC);
179     return PushImage(id, GenerateImageData(0, info, memory), skipBytes, nullptr, &properties);
180 }
181 
PushSharedMemory(uint64_t id,PixelMap & map)182 bool PixelMapStorage::PushSharedMemory(uint64_t id, PixelMap& map)
183 {
184     if (!map.GetFd()) {
185         return false;
186     }
187 
188     constexpr size_t skipBytes = 24u;
189     const auto size = static_cast<size_t>(map.GetByteCount());
190     const ImageProperties properties(map);
191     if (auto image = MapImage(*reinterpret_cast<const int32_t*>(map.GetFd()), size, PROT_READ)) {
192         auto ret = PushImage(id, GenerateImageData(0, image, size, map), skipBytes, nullptr, &properties);
193         UnmapImage(image, size);
194         return ret;
195     }
196     return false;
197 }
198 
PullDmaMemory(uint64_t id,const ImageInfo & info,PixelMemInfo & memory,size_t & skipBytes)199 bool PixelMapStorage::PullDmaMemory(uint64_t id, const ImageInfo& info, PixelMemInfo& memory, size_t& skipBytes)
200 {
201     skipBytes = 0u;
202     if (!ValidateBufferSize(memory)) {
203         return false;
204     }
205 
206     auto image = ImageCache::Get(id);
207     if (!image) {
208         return false;
209     }
210 
211     auto surfaceBuffer = SurfaceBuffer::Create();
212     if (!surfaceBuffer) {
213         return false;
214     }
215 
216     const BufferRequestConfig config = { .width = image->dmaWidth,
217         .height = image->dmaHeight,
218         .strideAlignment = image->dmaStride,
219         .format = image->dmaFormat,
220         .usage = image->dmaUsage };
221     surfaceBuffer->Alloc(config);
222 
223     memory.base = static_cast<uint8_t*>(surfaceBuffer->GetVirAddr());
224     if (!CopyImageData(image, memory.base, image->dmaSize)) {
225         return false;
226     }
227     // solve pink artefacts problem during replay (GPU reads texture when it's still not updated)
228     surfaceBuffer->FlushCache();
229 
230     memory.context = IncrementSurfaceBufferReference(surfaceBuffer);
231     skipBytes = image->parcelSkipBytes;
232     return true;
233 }
234 
PushDmaMemory(uint64_t id,const ImageInfo & info,const PixelMemInfo & memory,size_t skipBytes)235 bool PixelMapStorage::PushDmaMemory(uint64_t id, const ImageInfo& info, const PixelMemInfo& memory, size_t skipBytes)
236 {
237     auto surfaceBuffer = reinterpret_cast<SurfaceBuffer*>(memory.context);
238     auto buffer = surfaceBuffer ? surfaceBuffer->GetBufferHandle() : nullptr;
239     if (buffer) {
240         const auto pixels = GenerateImageData(id, reinterpret_cast<const uint8_t*>(surfaceBuffer->GetVirAddr()),
241             buffer->size, memory.isAstc, GetBytesPerPixel(info));
242         ImageProperties properties(info, AllocatorType::DMA_ALLOC);
243         return PushImage(id, pixels, skipBytes, buffer, &properties);
244     }
245     return false;
246 }
247 
PushDmaMemory(uint64_t id,PixelMap & map)248 bool PixelMapStorage::PushDmaMemory(uint64_t id, PixelMap& map)
249 {
250     const auto surfaceBuffer = reinterpret_cast<SurfaceBuffer*>(map.GetFd());
251     const auto buffer = surfaceBuffer ? surfaceBuffer->GetBufferHandle() : nullptr;
252     if (!buffer) {
253         return false;
254     }
255     const ImageProperties properties(map);
256     const auto pixels =
257         GenerateImageData(id, reinterpret_cast<const uint8_t*>(surfaceBuffer->GetVirAddr()), buffer->size, map);
258     MessageParcel parcel;
259     surfaceBuffer->WriteToMessageParcel(parcel);
260     return PushImage(id, pixels, parcel.GetReadableBytes(), buffer, &properties);
261 }
262 
PushHeapMemory(uint64_t id,const ImageInfo & info,const PixelMemInfo & memory,size_t skipBytes)263 bool PixelMapStorage::PushHeapMemory(uint64_t id, const ImageInfo& info, const PixelMemInfo& memory, size_t skipBytes)
264 {
265     ImageProperties properties(info, AllocatorType::HEAP_ALLOC);
266     return PushImage(id, GenerateImageData(0, info, memory), skipBytes, nullptr, &properties);
267 }
268 
PushHeapMemory(uint64_t id,PixelMap & map)269 bool PixelMapStorage::PushHeapMemory(uint64_t id, PixelMap& map)
270 {
271     if (!map.GetFd()) {
272         return false;
273     }
274 
275     constexpr size_t skipBytes = 24u;
276     const auto baseSize = static_cast<size_t>(const_cast<PixelMap&>(map).GetByteCount());
277     const ImageProperties properties(map);
278     const uint8_t *base = map.GetPixels();
279     if (base && baseSize) {
280         const auto pixels = GenerateImageData(0, base, baseSize, map);
281         return PushImage(id, pixels, skipBytes, nullptr, &properties);
282     }
283     return false;
284 }
285 
PullHeapMemory(uint64_t id,const ImageInfo & info,PixelMemInfo & memory,size_t & skipBytes)286 bool PixelMapStorage::PullHeapMemory(uint64_t id, const ImageInfo& info, PixelMemInfo& memory, size_t& skipBytes)
287 {
288     if (memory.bufferSize <= PixelMap::MIN_IMAGEDATA_SIZE) {
289         return false;
290     }
291 
292     auto retCode = PullSharedMemory(id, info, memory, skipBytes);
293 
294     constexpr size_t skipFdSize = 24u;
295     skipBytes = skipFdSize;
296 
297     return retCode;
298 }
299 
DefaultHeapMemory(uint64_t id,const ImageInfo & info,PixelMemInfo & memory,size_t & skipBytes)300 bool PixelMapStorage::DefaultHeapMemory(uint64_t id, const ImageInfo& info, PixelMemInfo& memory, size_t& skipBytes)
301 {
302     memory.allocatorType = AllocatorType::HEAP_ALLOC;
303     memory.base = reinterpret_cast<uint8_t*>(malloc(memory.bufferSize));
304     if (memory.base) {
305         memset_s(memory.base, memory.bufferSize, 0, memory.bufferSize);
306     }
307     memory.context = nullptr;
308 
309     constexpr size_t skipFdSize = 24u;
310     skipBytes = skipFdSize;
311     return true;
312 }
313 
EncodeSeqLZ4(const ImageData & source,ImageData & dst)314 int32_t PixelMapStorage::EncodeSeqLZ4(const ImageData& source, ImageData& dst)
315 {
316 #ifdef ROSEN_OHOS
317     int32_t dstCap = LZ4_compressBound(source.size());
318     ImageData buf;
319     buf.reserve(dstCap);
320 
321     auto start = reinterpret_cast<const char*>(source.data());
322     int32_t encodedSize = LZ4_compress_default(start, reinterpret_cast<char*>(buf.data()), source.size(), dstCap);
323     if (encodedSize < 0) {
324         HRPE("Error when encoding lz4");
325         return -1;
326     }
327 
328     dst.insert(dst.end(), buf.data(), buf.data() + encodedSize);
329     return encodedSize;
330 #else
331     HRPD("lz4 encoding is not supported on this platform");
332     return -1;
333 #endif
334 }
335 
EncodeJpeg(const ImageData & source,ImageData & dst,const ImageProperties & properties)336 int32_t PixelMapStorage::EncodeJpeg(const ImageData& source, ImageData& dst, const ImageProperties& properties)
337 {
338     Media::InitializationOptions opts = { .size = { .width = properties.width, .height = properties.height },
339         .srcPixelFormat = properties.GetFormat(),
340         .pixelFormat = Media::PixelFormat::RGBA_8888,
341         .alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE,
342         .srcRowStride = properties.stride };
343     auto sourceRgb = Media::PixelMap::Create(reinterpret_cast<const uint32_t*>(source.data()), source.size(), opts);
344     if (!sourceRgb) {
345         HRPE("Failed to create source to encode to rgb");
346         return -1;
347     }
348     uint32_t err = 0;
349     Media::ImagePacker imagePacker;
350     Media::PackOption option;
351     option.format = "image/jpeg";
352     ImageData dstRgb;
353     dstRgb.reserve(source.size());
354     err = imagePacker.StartPacking(static_cast<uint8_t*>(dstRgb.data()), source.size(), option);
355     if (err != 0) {
356         HRPE("Failed to start packing to jpeg, errcode %{public}u", err);
357         return -1;
358     }
359     err = imagePacker.AddImage(*sourceRgb);
360     if (err != 0) {
361         HRPE("Failed to AddImage, errcode %{public}u", err);
362         return -1;
363     }
364     int64_t encodedSize = 0;
365     err = imagePacker.FinalizePacking(encodedSize);
366     if (err != 0) {
367         HRPE("Failed to FinalizePacking, errcode %{public}u", err);
368         return -1;
369     }
370     dst.insert(dst.end(), dstRgb.data(), dstRgb.data() + encodedSize);
371     return encodedSize;
372 }
373 
ExtractAlpha(const ImageData & image,ImageData & alpha,const ImageProperties & properties)374 void PixelMapStorage::ExtractAlpha(const ImageData& image, ImageData& alpha, const ImageProperties& properties)
375 {
376     alpha.reserve(image.size() / ALPHA_OFFSET);
377     for (int32_t row = 0, rStart = 0; row < properties.height; ++row, rStart += properties.stride) {
378         for (int32_t pixIdx = 0, alphaIdx = rStart + RGB_OFFSET;
379                 pixIdx < properties.width; ++pixIdx, alphaIdx += ALPHA_OFFSET) {
380             alpha.emplace_back(image[alphaIdx]);
381         }
382     }
383 }
384 
PushImage(uint64_t id,const ImageData & data,size_t skipBytes,BufferHandle * buffer,const ImageProperties * properties)385 bool PixelMapStorage::PushImage(
386     uint64_t id, const ImageData& data, size_t skipBytes, BufferHandle* buffer, const ImageProperties* properties)
387 {
388     if (data.empty() || (buffer && ((buffer->width == 0) || (buffer->height == 0)))) {
389         return false;
390     }
391 
392     Image image;
393     image.parcelSkipBytes = skipBytes;
394 
395     JsonWriter json;
396     json.PushObject();
397     json["id"] = id;
398     if (!properties) {
399         json["type"] = std::string("HEAP");
400     } else if (properties->GetAllocType() == AllocatorType::SHARE_MEM_ALLOC) {
401         json["type"] = std::string("SHARED");
402     } else if (properties->GetAllocType() == AllocatorType::DMA_ALLOC) {
403         json["type"] = std::string("DMA");
404     } else {
405         json["type"] = std::string("HEAP");
406     }
407 
408     if (buffer) {
409         image.dmaSize = static_cast<size_t>(buffer->size);
410         image.dmaWidth = buffer->width;
411         image.dmaHeight = buffer->height;
412         image.dmaStride = buffer->stride;
413         image.dmaFormat = buffer->format;
414         image.dmaUsage = buffer->usage;
415 
416         json["width"] = buffer->width;
417         json["height"] = buffer->height;
418         json["stride"] = buffer->stride;
419         json["format"] = buffer->format;
420         json.PopObject();
421         RSProfiler::SendRSLogBase(RSProfilerLogType::PIXELMAP, json.GetDumpString());
422     } else if (properties) {
423         json["width"] = properties->width;
424         json["height"] = properties->height;
425         json["stride"] = properties->stride;
426         json["format"] = static_cast<int>(properties->format);
427         json.PopObject();
428         RSProfiler::SendRSLogBase(RSProfilerLogType::PIXELMAP, json.GetDumpString());
429     }
430 
431     EncodedType encodedType = EncodedType::NONE;
432     if (RSProfiler::IsWriteEmulationMode() && (RSProfiler::GetTextureRecordType() == TextureRecordType::JPEG ||
433         RSProfiler::GetTextureRecordType() == TextureRecordType::LZ4)) {
434         // COMPRESS WITH LZ4 OR JPEG
435         encodedType = TryEncodeTexture(properties, data, image);
436     }
437     if (encodedType == EncodedType::NONE) {
438         // NO COMPRESION
439         image.data = data;
440     }
441 
442     return ImageCache::Add(id, std::move(image));
443 }
444 
TryEncodeTexture(const ImageProperties * properties,const ImageData & data,Image & image)445 EncodedType PixelMapStorage::TryEncodeTexture(const ImageProperties* properties, const ImageData& data, Image& image)
446 {
447     EncodedType encodedType = EncodedType::NONE;
448 
449     image.data.resize(sizeof(TextureHeader));
450     if (properties && RSProfiler::GetTextureRecordType() == TextureRecordType::JPEG &&
451         (properties->GetFormat() == Media::PixelFormat::RGBA_8888 ||
452         properties->GetFormat() == Media::PixelFormat::BGRA_8888) &&
453         static_cast<int32_t>(data.size()) == properties->stride * properties->height) {
454         int32_t rgbEncodedSize = EncodeJpeg(data, image.data, *properties);
455         if (rgbEncodedSize != -1) {
456             ImageData alpha;
457             ExtractAlpha(data, alpha, *properties);
458             int32_t alphaEncodedSize = EncodeSeqLZ4(alpha, image.data);
459             if (alphaEncodedSize != -1) {
460                 encodedType = EncodedType::JPEG;
461                 TextureHeader* header = reinterpret_cast<TextureHeader*>(image.data.data());
462                 header->magicNumber = 'JPEG';
463                 header->properties = *properties;
464                 header->totalOriginalSize = data.size();
465                 header->rgbEncodedSize = rgbEncodedSize;
466                 header->alphaOriginalSize = alpha.size();
467                 header->alphaEncodedSize = alphaEncodedSize;
468             }
469         }
470     }
471     if (encodedType == EncodedType::NONE) {
472         int32_t encodedSize = EncodeSeqLZ4(data, image.data);
473         if (encodedSize != -1) {
474             encodedType = EncodedType::XLZ4;
475             TextureHeader* header = reinterpret_cast<TextureHeader*>(image.data.data());
476             header->magicNumber = 'XLZ4';
477             header->totalOriginalSize = data.size();
478         }
479     }
480     return encodedType;
481 }
482 
ValidateBufferSize(const PixelMemInfo & memory)483 bool PixelMapStorage::ValidateBufferSize(const PixelMemInfo& memory)
484 {
485     return (memory.bufferSize > 0) && (static_cast<size_t>(memory.bufferSize) <= Image::maxSize);
486 }
487 
GetBytesPerPixel(const ImageInfo & info)488 uint32_t PixelMapStorage::GetBytesPerPixel(const ImageInfo& info)
489 {
490     const auto rowPitch = PixelMap::GetRGBxRowDataSize(info);
491     return (rowPitch > 0) ? static_cast<uint32_t>(rowPitch / info.size.width) : 0u;
492 }
493 
MapImage(int32_t file,size_t size,int32_t flags)494 uint8_t* PixelMapStorage::MapImage(int32_t file, size_t size, int32_t flags)
495 {
496     auto image = ::mmap(nullptr, size, flags, MAP_SHARED, file, 0);
497     return (image != MAP_FAILED) ? reinterpret_cast<uint8_t*>(image) : nullptr; // NOLINT
498 }
499 
UnmapImage(void * image,size_t size)500 void PixelMapStorage::UnmapImage(void* image, size_t size)
501 {
502     if (IsDataValid(image, size)) {
503         ::munmap(image, size);
504     }
505 }
506 
IncrementSurfaceBufferReference(sptr<SurfaceBuffer> & buffer)507 SurfaceBuffer* PixelMapStorage::IncrementSurfaceBufferReference(sptr<SurfaceBuffer>& buffer)
508 {
509     if (auto object = buffer.GetRefPtr()) {
510         object->IncStrongRef(object);
511         return object;
512     }
513     return nullptr;
514 }
515 
IsDataValid(const void * data,size_t size)516 bool PixelMapStorage::IsDataValid(const void* data, size_t size)
517 {
518     return data && (size > 0);
519 }
520 
CopyImageData(const uint8_t * srcImage,size_t srcSize,uint8_t * dstImage,size_t dstSize)521 bool PixelMapStorage::CopyImageData(const uint8_t* srcImage, size_t srcSize, uint8_t* dstImage, size_t dstSize)
522 {
523     if (!srcImage || !dstImage || (srcSize == 0) || (dstSize == 0) || (srcSize > dstSize)) {
524         return false;
525     }
526 
527     if (dstSize == srcSize) {
528         return Utils::Move(dstImage, dstSize, srcImage, srcSize);
529     }
530 
531     for (size_t offset = 0; offset < dstSize;) {
532         const size_t size = std::min(dstSize - offset, srcSize);
533         if (!Utils::Move(dstImage + offset, size, srcImage, size)) {
534             return false;
535         }
536         offset += size;
537     }
538 
539     return true;
540 }
541 
CopyImageData(const ImageData & data,uint8_t * dstImage,size_t dstSize)542 bool PixelMapStorage::CopyImageData(const ImageData& data, uint8_t* dstImage, size_t dstSize)
543 {
544     return CopyImageData(data.data(), data.size(), dstImage, dstSize);
545 }
546 
ReplaceAlpha(ImageData & image,ImageData & alpha,const ImageProperties & properties)547 void PixelMapStorage::ReplaceAlpha(ImageData& image, ImageData& alpha, const ImageProperties& properties)
548 {
549     int32_t i = 0;
550     for (int32_t row = 0, rStart = 0; row < properties.height; ++row, rStart += properties.stride) {
551         for (int32_t pixIdx = 0, alphaIdx = rStart + RGB_OFFSET; pixIdx < properties.width;
552                 ++pixIdx, alphaIdx += ALPHA_OFFSET) {
553             image[alphaIdx] = alpha[i++];
554         }
555     }
556 }
557 
MakeStride(ImageData & noPadding,ImageData & dst,const ImageProperties & properties,int32_t pixelBytes)558 int32_t PixelMapStorage::MakeStride(
559     ImageData& noPadding, ImageData& dst, const ImageProperties& properties, int32_t pixelBytes)
560 {
561     int32_t padding = properties.stride - properties.width * pixelBytes;
562     for (int32_t row = 0; row < properties.height; row++) {
563         int32_t rowStart = properties.width * pixelBytes * row;
564         int32_t nextRowStart = properties.width * pixelBytes + rowStart;
565         dst.insert(dst.end(), noPadding.begin() + rowStart, noPadding.begin() + nextRowStart);
566         dst.insert(dst.end(), padding, 0);
567     }
568 
569     return dst.size();
570 }
571 
DecodeSeqLZ4(const char * source,ImageData & dst,int32_t sourceSize,int32_t originalSize)572 int32_t PixelMapStorage::DecodeSeqLZ4(const char* source, ImageData& dst, int32_t sourceSize, int32_t originalSize)
573 {
574 #ifdef ROSEN_OHOS
575     dst.resize(originalSize);
576     int cnt = LZ4_decompress_safe_partial(
577         source, reinterpret_cast<char*>(dst.data()), sourceSize, originalSize, originalSize);
578     return cnt;
579 #else
580     HRPE("lz4 encoding is not supported on this platform");
581     return -1;
582 #endif
583 }
584 
DecodeJpeg(const char * source,ImageData & dst,int32_t sourceSize,const ImageProperties & properties)585 int32_t PixelMapStorage::DecodeJpeg(
586     const char* source, ImageData& dst, int32_t sourceSize, const ImageProperties& properties)
587 {
588     Media::SourceOptions opts = { .formatHint = "image/jpeg",
589         .pixelFormat = properties.GetFormat(),
590         .size = { .width = properties.width, .height = properties.height } };
591     uint32_t err;
592     auto src = Media::ImageSource::CreateImageSource(reinterpret_cast<const uint8_t*>(source), sourceSize, opts, err);
593     if (!src || err != 0) {
594         HRPE("Error when creating source, errcode %{public}u", err);
595         return -1;
596     }
597     Media::DecodeOptions dopts;
598     auto pmap = src->CreatePixelMap(dopts, err);
599     if (!pmap || err != 0) {
600         HRPE("Error when creating pixelmap, errcode %{public}u", err);
601         return -1;
602     }
603     ImageData noPadding;
604     auto reserveSize = pmap->GetByteCount();
605     if (reserveSize <= 0) {
606         HRPE("Error when reading pixels, GetByteCount is not positive");
607         return -1;
608     }
609     noPadding.reserve(reserveSize);
610     err = pmap->ReadPixels(reserveSize, noPadding.data());
611     if (err != 0) {
612         HRPE("Error when reading pixels, errcode %{public}u", err);
613         return -1;
614     }
615 
616     return MakeStride(noPadding, dst, properties, ALPHA_OFFSET);
617 }
618 
CopyImageData(Image * image,uint8_t * dstImage,size_t dstSize)619 bool PixelMapStorage::CopyImageData(Image* image, uint8_t* dstImage, size_t dstSize)
620 {
621     if (!image) {
622         return false;
623     }
624 
625     TextureHeader* header = reinterpret_cast<TextureHeader*>(image->data.data());
626     const char* srcStart = reinterpret_cast<const char*>(image->data.data()) + sizeof(TextureHeader);
627     ImageData result;
628 
629     if (header->magicNumber == 'JPEG' && image->data.size() >= sizeof(TextureHeader)) {
630         int32_t decodedTotalBytes = DecodeJpeg(srcStart, result, header->rgbEncodedSize, header->properties);
631         if (decodedTotalBytes == header->totalOriginalSize) {
632             ImageData alpha;
633             const char* alphaStart = srcStart + header->rgbEncodedSize;
634             int32_t decodedAlphaBytes =
635                 DecodeSeqLZ4(alphaStart, alpha, header->alphaEncodedSize, header->alphaOriginalSize);
636             if (decodedAlphaBytes == header->alphaOriginalSize) {
637                 ReplaceAlpha(result, alpha, header->properties);
638                 image->data.clear();
639                 image->data.insert(image->data.end(), result.begin(), result.end());
640             } else {
641                 HRPE("Error when decoding alpha got %{public}d bytes, expected %{public}d bytes", decodedAlphaBytes,
642                     header->alphaOriginalSize);
643             }
644         } else {
645             HRPE("Error when decoding rgb got %{public}d bytes, expected %{public}d bytes", decodedTotalBytes,
646                 header->totalOriginalSize);
647         }
648     } else if (header->magicNumber == 'XLZ4' && image->data.size() >= sizeof(TextureHeader)) {
649         int32_t sourceSize = image->data.size() - sizeof(TextureHeader);
650         int32_t decodedTotalBytes = DecodeSeqLZ4(srcStart, result, sourceSize, header->totalOriginalSize);
651         if (decodedTotalBytes == header->totalOriginalSize) {
652             image->data.clear();
653             image->data.insert(image->data.end(), result.begin(), result.end());
654         } else {
655             HRPE("Error when decoding lz4 got %{public}d bytes, expected %{public}d bytes", decodedTotalBytes,
656                 header->totalOriginalSize);
657         }
658     } else {
659         // assume image was not encoded, do nothing
660     }
661 
662     return CopyImageData(image->data, dstImage, dstSize);
663 }
664 
GenerateRawCopy(const uint8_t * data,size_t size)665 ImageData PixelMapStorage::GenerateRawCopy(const uint8_t* data, size_t size)
666 {
667     ImageData out;
668     if (IsDataValid(data, size)) {
669         out.insert(out.end(), data, data + size);
670     }
671     return out;
672 }
673 
GenerateMiniatureAstc(const uint8_t * data,size_t size)674 ImageData PixelMapStorage::GenerateMiniatureAstc(const uint8_t* data, size_t size)
675 {
676     constexpr uint32_t astcBytesPerPixel = 16u;
677     return GenerateRawCopy(data, astcBytesPerPixel);
678 }
679 
GenerateMiniature(uint64_t uniqueId,const uint8_t * data,size_t size,uint32_t pixelBytes)680 ImageData PixelMapStorage::GenerateMiniature(uint64_t uniqueId, const uint8_t* data, size_t size, uint32_t pixelBytes)
681 {
682     if (!IsDataValid(data, size)) {
683         return {};
684     }
685 
686     constexpr uint32_t rgbaBytesPerPixel = 4u;
687     constexpr uint32_t pixelBytesThreshold = 256u; // in case the pixelBytes field in the map has invalid value
688     const uint32_t bytesPerPixel =
689         ((pixelBytes > 0) && (pixelBytes < pixelBytesThreshold)) ? pixelBytes : rgbaBytesPerPixel;
690 
691     const auto pixelCount = size / bytesPerPixel;
692 
693     if (uniqueId) { // for DMA textures determine their color by uniqueId without data averaging for stability reason
694         constexpr int defaultFillValue = 0x7F;
695         constexpr int oneByteBits = 8;
696         constexpr int halfByteBits = 4;
697         uint32_t color = static_cast<uint32_t>(Utils::ExtractPid(uniqueId)) << oneByteBits;
698         color ^= Utils::ExtractNodeId(uniqueId);
699         color ^= color << halfByteBits;
700         ImageData out(bytesPerPixel, defaultFillValue);
701         for (uint32_t i = 0; i < bytesPerPixel; i++) {
702             out[i] ^= static_cast<uint8_t>(color);
703             color >>= oneByteBits;
704         }
705         return out;
706     }
707 
708     std::vector<uint64_t> averageValue(bytesPerPixel, 0);
709     constexpr uint32_t sampleCount = 100u;
710     for (uint32_t sample = 0; sample < sampleCount; sample++) {
711         for (uint32_t channel = 0; channel < bytesPerPixel; channel++) {
712             const size_t dataIdx = (sample * pixelCount / sampleCount) * bytesPerPixel + channel;
713             averageValue[channel] += (dataIdx < size) ? data[dataIdx] : 0;
714         }
715     }
716 
717     ImageData out(bytesPerPixel, 0);
718     for (uint32_t i = 0; i < bytesPerPixel; i++) {
719         out[i] = static_cast<uint8_t>(averageValue[i] / sampleCount);
720     }
721     return out;
722 }
723 
GenerateImageData(uint64_t uniqueId,const uint8_t * data,size_t size,const PixelMap & map)724 ImageData PixelMapStorage::GenerateImageData(uint64_t uniqueId, const uint8_t* data, size_t size, const PixelMap& map)
725 {
726     const auto bytesPerPixel = static_cast<uint32_t>(const_cast<PixelMap&>(map).GetPixelBytes());
727     return GenerateImageData(uniqueId, data, size, const_cast<PixelMap&>(map).IsAstc(), bytesPerPixel);
728 }
729 
GenerateImageData(uint64_t uniqueId,const ImageInfo & info,const PixelMemInfo & memory)730 ImageData PixelMapStorage::GenerateImageData(uint64_t uniqueId, const ImageInfo& info, const PixelMemInfo& memory)
731 {
732     return GenerateImageData(uniqueId,
733         memory.base, static_cast<size_t>(memory.bufferSize), memory.isAstc, GetBytesPerPixel(info));
734 }
735 
GenerateImageData(uint64_t uniqueId,const uint8_t * data,size_t size,bool isAstc,uint32_t pixelBytes)736 ImageData PixelMapStorage::GenerateImageData(
737     uint64_t uniqueId, const uint8_t* data, size_t size, bool isAstc, uint32_t pixelBytes)
738 {
739     if (RSProfiler::GetTextureRecordType() != TextureRecordType::ONE_PIXEL) {
740         return GenerateRawCopy(data, size);
741     }
742 
743     return isAstc ? GenerateMiniatureAstc(data, size) : GenerateMiniature(uniqueId, data, size, pixelBytes);
744 }
745 
746 // Profiler
747 
SkipPixelMap(Parcel & parcel)748 bool RSProfiler::SkipPixelMap(Parcel& parcel)
749 {
750     if (IsEnabled() && IsWriteMode()) {
751         std::shared_ptr<Media::PixelMap> pixelMap;
752         RSMarshallingHelper::Unmarshalling(parcel, pixelMap);
753         return true;
754     }
755     return false;
756 }
757 
MarshalPixelMap(Parcel & parcel,const std::shared_ptr<Media::PixelMap> & map)758 bool RSProfiler::MarshalPixelMap(Parcel& parcel, const std::shared_ptr<Media::PixelMap>& map)
759 {
760     if (!map) {
761         return false;
762     }
763 
764     const bool profilerEnabled = RSSystemProperties::GetProfilerEnabled();
765     const bool pixelCheckEnabled = RSSystemProperties::GetProfilerPixelCheckMode();
766     uint8_t flags = 0;
767     if (profilerEnabled) {
768         flags |= PIXELMAP_FLAG_PROFILER;
769         if (pixelCheckEnabled) {
770             flags |= PIXELMAP_FLAG_PIXEL_CHECK;
771         }
772     }
773     if (!parcel.WriteUint8(flags)) {
774         HRPE("MarshalPixelMap: Unable to write flags");
775         return false;
776     }
777 
778     if (!profilerEnabled) {
779         return map->Marshalling(parcel);
780     }
781 
782     uint64_t id =
783         IsWriteEmulationMode() ? ImageCache::New() : Utils::ComposeNodeId(Utils::GetPid(), map->GetUniqueId());
784 
785     constexpr uint64_t flagIsImage = 1ull << 62;
786     id |= flagIsImage;
787 
788     if (!parcel.WriteUint64(id)) {
789         HRPE("MarshalPixelMap: Unable to write id");
790         return false;
791     }
792 
793     if (pixelCheckEnabled) {
794         if (!Media::PixelMapRecordParcel::MarshallingPixelMapForRecord(parcel, *(map.get()))) {
795             HRPE("MarshalPixelMap: Unable to marshal pixelmap for pixel check mode");
796             return false;
797         }
798     } else if (!map->Marshalling(parcel)) {
799         HRPE("MarshalPixelMap: Unable to marshal pixelmap");
800         return false;
801     }
802 
803     if (IsSharedMemoryEnabled()) {
804         return true;
805     }
806 
807     if (!IsRecordAbortRequested() && (IsWriteMode() || IsWriteEmulationMode())) {
808         if (!PixelMapStorage::Push(id, *map)) {
809             RequestRecordAbort();
810         }
811     }
812     return true;
813 }
814 
UnmarshalPixelMapNstd(Parcel & parcel,std::function<int (Parcel & parcel,std::function<int (Parcel &)> readFdDefaultFunc)> readSafeFdFunc)815 Media::PixelMap* RSProfiler::UnmarshalPixelMapNstd(Parcel& parcel,
816     std::function<int(Parcel& parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc)
817 {
818     const uint64_t id = parcel.ReadUint64();
819 
820     if (IsRecordAbortRequested()) {
821         return Media::PixelMapRecordParcel::UnmarshallingPixelMapForRecord(parcel, readSafeFdFunc);
822     }
823 
824     ImageInfo info;
825     PixelMemInfo memory;
826     PIXEL_MAP_ERR error;
827     auto map = Media::PixelMapRecordParcel::StartUnmarshalling(parcel, info, memory, error);
828 
829     if ((IsReadMode() || IsReadEmulationMode()) && IsParcelMock(parcel)) {
830         size_t skipBytes = 0u;
831         if (PixelMapStorage::Pull(id, info, memory, skipBytes)) {
832             parcel.SkipBytes(skipBytes);
833             return Media::PixelMapRecordParcel::FinishUnmarshalling(map, parcel, info, memory, error);
834         }
835     }
836 
837     const auto parcelPosition = parcel.GetReadPosition();
838     if (map && !Media::PixelMapRecordParcel::ReadMemInfoFromParcel(parcel, memory, error, readSafeFdFunc)) {
839         delete map;
840         return nullptr;
841     }
842 
843     if (IsWriteMode() || IsWriteEmulationMode()) {
844         if (!PixelMapStorage::Push(id, info, memory, parcel.GetReadPosition() - parcelPosition)) {
845             RequestRecordAbort();
846         }
847     }
848     return Media::PixelMapRecordParcel::FinishUnmarshalling(map, parcel, info, memory, error);
849 }
850 
UnmarshalPixelMap(Parcel & parcel,std::function<int (Parcel & parcel,std::function<int (Parcel &)> readFdDefaultFunc)> readSafeFdFunc)851 Media::PixelMap* RSProfiler::UnmarshalPixelMap(Parcel& parcel,
852     std::function<int(Parcel& parcel, std::function<int(Parcel&)> readFdDefaultFunc)> readSafeFdFunc)
853 {
854     uint8_t flags;
855     if (!parcel.ReadUint8(flags)) {
856         HRPE("UnmarshalPixelMap: Unable to read flags");
857         return nullptr;
858     }
859 
860     bool profilerEnabled = flags & PIXELMAP_FLAG_PROFILER;
861     if (!profilerEnabled) {
862         return PixelMap::UnmarshallingWithIsDisplay(parcel, readSafeFdFunc, true);
863     }
864 
865     bool pixelCheckEnabled = flags & PIXELMAP_FLAG_PIXEL_CHECK;
866     if (pixelCheckEnabled) {
867         return UnmarshalPixelMapNstd(parcel, readSafeFdFunc);
868     }
869 
870     const uint64_t id = parcel.ReadUint64();
871 
872     if (IsRecordAbortRequested()) {
873         return PixelMap::Unmarshalling(parcel, readSafeFdFunc);
874     }
875 
876     ImageInfo info;
877     PixelMemInfo memory;
878     PIXEL_MAP_ERR error;
879     auto map = PixelMap::StartUnmarshalling(parcel, info, memory, error);
880 
881     if (IsPlaybackParcel(parcel)) {
882         size_t skipBytes = 0u;
883         if (PixelMapStorage::Pull(id, info, memory, skipBytes)) {
884             parcel.SkipBytes(skipBytes);
885             return PixelMap::FinishUnmarshalling(map, parcel, info, memory, error);
886         }
887     }
888 
889     const auto parcelPosition = parcel.GetReadPosition();
890     if (map && !PixelMap::ReadMemInfoFromParcel(parcel, memory, error, readSafeFdFunc)) {
891         delete map;
892         return nullptr;
893     }
894 
895     if (IsWriteMode() || IsWriteEmulationMode()) {
896         if (!PixelMapStorage::Push(id, info, memory, parcel.GetReadPosition() - parcelPosition)) {
897             RequestRecordAbort();
898         }
899     }
900 
901     auto retPixelMap = PixelMap::FinishUnmarshalling(map, parcel, info, memory, error);
902     if (retPixelMap && (IsWriteMode() || IsWriteEmulationMode()) && retPixelMap->IsYuvFormat()) {
903         Media::YUVDataInfo yuvInfo;
904         retPixelMap->GetImageYUVInfo(yuvInfo);
905         LogYUVDataInfo(id, yuvInfo);
906     }
907     return retPixelMap;
908 }
909 
LogYUVDataInfo(uint64_t id,const Media::YUVDataInfo & yuvInfo)910 void RSProfiler::LogYUVDataInfo(uint64_t id, const Media::YUVDataInfo& yuvInfo)
911 {
912     JsonWriter json;
913 
914     json.PushObject();
915     json["id"] = id;
916     json["imageSizeW"] = yuvInfo.imageSize.width;
917     json["imageSizeH"] = yuvInfo.imageSize.height;
918     json["yWidth"] = yuvInfo.yWidth;
919     json["yHeight"] = yuvInfo.yHeight;
920     json["uvWidth"] = yuvInfo.uvWidth;
921     json["uvHeight"] = yuvInfo.uvHeight;
922     json["yStride"] = yuvInfo.yStride;
923     json["uStride"] = yuvInfo.uStride;
924     json["vStride"] = yuvInfo.vStride;
925     json["uvStride"] = yuvInfo.uvStride;
926     json["yOffset"] = yuvInfo.yOffset;
927     json["uOffset"] = yuvInfo.uOffset;
928     json["vOffset"] = yuvInfo.vOffset;
929     json["uvOffset"] = yuvInfo.uvOffset;
930     json.PopObject();
931 
932     RSProfiler::SendRSLogBase(RSProfilerLogType::PIXELMAP_YUV, json.GetDumpString());
933 }
934 
935 } // namespace OHOS::Rosen