/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkJpegCodec_MTK_DEFINED #define SkJpegCodec_MTK_DEFINED #include "include/codec/SkCodec.h" #include "include/codec/SkEncodedOrigin.h" #include "include/core/SkColorSpace.h" #include "include/core/SkEncodedImageFormat.h" #include "include/core/SkRect.h" #include "include/core/SkSize.h" #include "include/core/SkTypes.h" #include "include/core/SkYUVAPixmaps.h" #include "include/private/SkEncodedInfo.h" #include "include/private/base/SkTemplates.h" #include "src/codec/SkSwizzler.h" #include "AppInsight.h" #include #include #include #ifdef MTK_JPEG_HW_REGION_RESIZER #include #include #include #include #include #define ION_HEAP_MULTIMEDIA_MASK (1 << 10) #define MAX_HEAP_COUNT ION_HEAP_TYPE_CUSTOM using namespace AppInsight; class SkBufMalloc { public: SkBufMalloc(int ionClientHnd, BufferAllocator* bufferAllocator): fIonAllocHnd(-1), fIonClientHnd(ionClientHnd), fBufferAllocator(bufferAllocator), fAddr(NULL), fShareFD(-1), fSize(0), fStreamSize(0), fColorType(kRGBA_8888_SkColorType), fAlignment(0) { } ~SkBufMalloc() noexcept(false) { free(); } void* reset(size_t size) { int ret; if(fAddr != NULL) { free(); } fSize = size; if (fIonClientHnd >= 0) { ret = ion_alloc(fIonClientHnd, size, fAlignment, ION_HEAP_MULTIMEDIA_MASK, ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC, &fIonAllocHnd); if (ret) { SkDebugf("SkBufMalloc::ion_alloc failed (%d, %zu, %d)\n", fIonClientHnd, size, fIonAllocHnd); return NULL; } ret = ion_map(fIonClientHnd, fIonAllocHnd, size, PROT_READ | PROT_WRITE, MAP_SHARED, 0, &fAddr, &fShareFD); if (ret) { SkDebugf("SkBufMalloc::ion_mmap failed (%d, %zu, %d)\n", fIonClientHnd, size, fShareFD); ret = ion_free(fIonClientHnd, fIonAllocHnd); return NULL; } } else { fShareFD = DmabufHeapAlloc(fBufferAllocator, "mtk_mm", fSize, 0, 0); if (fShareFD < 0) { SkDebugf("SkBufMalloc DmabufHeapAlloc fail, bufferallocator %p fd: %d size: %zu\n", fBufferAllocator, fShareFD, size); fShareFD = -1; return NULL; } /* Create memory mapped buffer for the buffer fd */ fAddr = (unsigned char *)mmap(NULL, fSize, PROT_READ|PROT_WRITE, MAP_SHARED, fShareFD, 0); if (fAddr == MAP_FAILED) { SkDebugf("SkBufMalloc mmap failed (%zu, %d)\n", size, fShareFD); close(fShareFD); return NULL; } } return fAddr; } void free() { if (fIonClientHnd >= 0) { if(fAddr != NULL) { int ret = munmap(fAddr, fSize); if (ret < 0) SkDebugf("SkBufMalloc::ion_munmap failed (%d, %p, %zu)\n", fIonClientHnd, fAddr, fSize); else fAddr = NULL; } if (fShareFD != -1) { if (close(fShareFD)) { SkDebugf("SkBufMalloc close failed (%d, %d)\n", fIonClientHnd, fShareFD); } } if (fIonAllocHnd != -1) { if (ion_free(fIonClientHnd, fIonAllocHnd)) { SkDebugf("SkBufMalloc::ion_free failed (%d %d)\n", fIonClientHnd, fIonAllocHnd); } } } else { if(fAddr != NULL) { int ret = munmap(fAddr, fSize); if (ret < 0) SkDebugf("SkBufMalloc munmap failed (%p, %zu)\n", fAddr, fSize); else fAddr = NULL; } if (fShareFD != -1) { if (close(fShareFD)) { SkDebugf("SkBufMalloc close failed (%d)\n", fShareFD); } } } } void setStreamSize(int streamSize) { fStreamSize = streamSize; } void setColor(SkColorType color) { fColorType = color; } void setAlignment(size_t align) { fAlignment = align; } void* getAddr() { return fAddr; } int getFD() { return fShareFD; } size_t getSize() { return fSize; } size_t getStreamSize() { return fStreamSize; } ion_user_handle_t getIonAllocHnd() { return fIonAllocHnd; } SkColorType getColor() { return fColorType; } private: ion_user_handle_t fIonAllocHnd; int fIonClientHnd; BufferAllocator* fBufferAllocator; unsigned char* fAddr; int fShareFD; size_t fSize; size_t fStreamSize; SkColorType fColorType; size_t fAlignment; }; #endif class JpegDecoderMgr_MTK; class SkSampler; class SkStream; class SkSwizzler; struct SkGainmapInfo; struct SkImageInfo; /* * * This class implements the decoding for jpeg images * */ class SkJpegCodec : public SkCodec { public: ~SkJpegCodec() override; static bool IsJpeg(const void*, size_t); /* * Assumes IsJpeg was called and returned true * Takes ownership of the stream */ static std::unique_ptr MakeFromStream(std::unique_ptr, Result*); protected: /* * Recommend a set of destination dimensions given a requested scale */ SkISize onGetScaledDimensions(float desiredScale) const override; /* * Initiates the jpeg decode */ Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, int*) override; bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes&, SkYUVAPixmapInfo*) const override; Result onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) override; SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kJPEG; } bool onRewind() override; bool onDimensionsSupported(const SkISize&) override; bool conversionSupported(const SkImageInfo&, bool, bool) override; bool onGetGainmapInfo(SkGainmapInfo* info, std::unique_ptr* gainmapImageStream) override; private: /* * Allows SkRawCodec to communicate the color profile from the exif data. */ static std::unique_ptr MakeFromStream(std::unique_ptr, Result*, std::unique_ptr defaultColorProfile); /* * Read enough of the stream to initialize the SkJpegCodec. * Returns a bool representing success or failure. * * @param codecOut * If this returns true, and codecOut was not nullptr, * codecOut will be set to a new SkJpegCodec. * * @param decoderMgrOut * If this returns true, and codecOut was nullptr, * decoderMgrOut must be non-nullptr and decoderMgrOut will be set to a new * JpegDecoderMgr_MTK pointer. * * @param stream * Deleted on failure. * codecOut will take ownership of it in the case where we created a codec. * Ownership is unchanged when we set decoderMgrOut. * * @param defaultColorProfile * If the jpeg does not have an embedded color profile, the image data should * be tagged with this color profile. */ static Result ReadHeader(SkStream* stream, SkCodec** codecOut, JpegDecoderMgr_MTK** decoderMgrOut, std::unique_ptr defaultColorProfile); /* * Creates an instance of the decoder * Called only by NewFromStream * * @param info contains properties of the encoded data * @param stream the encoded image data * @param decoderMgr holds decompress struct, src manager, and error manager * takes ownership * @param origin indicates the image orientation as specified in Exif metadata. * @param xmpMetadata holds the XMP metadata included in the image, if any. */ SkJpegCodec(SkEncodedInfo&& info, std::unique_ptr stream, JpegDecoderMgr_MTK* decoderMgr, SkEncodedOrigin origin); void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options, bool needsCMYKToRGB); bool SK_WARN_UNUSED_RESULT allocateStorage(const SkImageInfo& dstInfo); int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count, const Options&); #ifdef MTK_JPEG_HW_REGION_RESIZER int readRows_MTK(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count, const Options&); #endif /* * Scanline decoding. */ SkSampler* getSampler(bool createIfNecessary) override; Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options) override; int onGetScanlines(void* dst, int count, size_t rowBytes) override; bool onSkipScanlines(int count) override; std::unique_ptr fDecoderMgr; // We will save the state of the decompress struct after reading the header. // This allows us to safely call onGetScaledDimensions() at any time. const int fReadyState; skia_private::AutoTMalloc fStorage; uint8_t* fSwizzleSrcRow = nullptr; uint32_t* fColorXformSrcRow = nullptr; // libjpeg-turbo provides some subsetting. In the case that libjpeg-turbo // cannot take the exact the subset that we need, we will use the swizzler // to further subset the output from libjpeg-turbo. SkIRect fSwizzlerSubset = SkIRect::MakeEmpty(); std::unique_ptr fSwizzler; friend class SkRawCodec; using INHERITED = SkCodec; #ifdef MTK_JPEG_HW_REGION_RESIZER int fIonClientHnd; BufferAllocator* fBufferAllocator; int fISOSpeedRatings; SkBufMalloc* fBufferStorage; SkBufMalloc* fBitstreamBuf; SkStream* fMemStream; bool fIsSampleDecode; unsigned int fSampleDecodeY; bool fFirstTileDone; bool fUseHWResizer; bool fEnTdshp; unsigned int fRegionHeight; InfoDump fInfoDump; #endif }; #endif