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