/* Copyright Statement: * * This software/firmware and related documentation ("MediaTek Software") are * protected under relevant copyright laws. The information contained herein is * confidential and proprietary to MediaTek Inc. and/or its licensors. Without * the prior written permission of MediaTek inc. and/or its licensors, any * reproduction, modification, use or disclosure of MediaTek Software, and * information contained herein, in whole or in part, shall be strictly * prohibited. * * MediaTek Inc. (C) 2021. All rights reserved. * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. * * The following software/firmware and/or related documentation ("MediaTek * Software") have been modified by MediaTek Inc. All revisions are subject to * any receiver's applicable license agreements with MediaTek Inc. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "SkiaDitherEffect.h" #include #include #include #include #include #include #include #include #include #include using namespace android; using android::hardware::graphics::common::V1_1::BufferUsage; namespace android { namespace renderengine { namespace skia { /* MTK_SKIA_DITHER_EFFECT_DEBUG Once defined, the dither shader string could be override for debugging. */ // #define MTK_SKIA_DITHER_EFFECT_DEBUG /* MTK_SKIA_DITHER_BLUE_NOISE_TABLE Once define, blue noise will be used (64x64 bytes). /system/etc/HBMNoiseTable is required. If this option is not defined, the dither table is from skia dither (8x8 bytes). */ // #define MTK_SKIA_DITHER_BLUE_NOISE_TABLE #ifdef MTK_IN_DISPLAY_FINGERPRINT bool SkiaDitherEffect::isInitOK() { return mInitOK; } SkiaDitherEffect::~SkiaDitherEffect(){ } SkiaDitherEffect::SkiaDitherEffect() { bool initOK = true; #ifdef MTK_SKIA_DITHER_BLUE_NOISE_TABLE static unsigned char ditherTable[64 * 64] = {0}; FILE* fp = fopen("/system/etc/HBMNoiseTable","rb"); if (fp) { size_t result = fread(ditherTable, 1, sizeof(ditherTable), fp); if (result != sizeof(ditherTable)) { ALOGE("HBMNoiseTable size is not correct (%zu)", result); initOK = false; } int ret = fclose(fp); if (CC_UNLIKELY(ret != 0)) { ALOGE("%s(), fclose fail", __FUNCTION__); initOK = false; } } else { ALOGE("open file /system/etc/HBMNoiseTable failed (%s)", strerror(errno)); initOK = false; } mDitherBmp.setInfo(SkImageInfo::MakeA8(64, 64)); mDitherBmp.setPixels(const_cast(ditherTable)); mDitherBmp.setImmutable(); #else static unsigned char ditherTable[8*8] = {0}; // following dither table is from Skia dither for (int x = 0; x < 8; ++x) { for (int y = 0; y < 8; ++y) { unsigned int m = (y & 1) << 5 | (x & 1) << 4 | (y & 2) << 2 | (x & 2) << 1 | (y & 4) >> 1 | (x & 4) >> 2; float value = float(m) * 1.0 / 64.0 - 63.0 / 128.0; ditherTable[y * 8 + x] = (uint8_t)((value + 0.5) * 255.f + 0.5f); } } mDitherBmp.setInfo(SkImageInfo::MakeA8(8, 8)); mDitherBmp.setPixels(const_cast(ditherTable)); mDitherBmp.setImmutable(); #endif mInitOK = initOK; } sk_sp SkiaDitherEffect::makeImage(GrDirectContext* context){ static GrDirectContext* current_context = nullptr; if (current_context != context) { mDitherImage = SkImage::MakeFromBitmap(mDitherBmp)->makeTextureImage(context); current_context = context; } return mDitherImage; } sk_sp SkiaDitherEffect::createDitherShader(GrDirectContext* grContext, sk_sp input, const float ditherAlpha) { sk_sp ditherImage = makeImage(grContext); if (ditherImage == nullptr){ ALOGE("%s(), makeImage fail", __FUNCTION__); } SkString ditherString(R"( uniform shader input; uniform shader table; uniform float ditherAlpha; half4 main(float2 xy) { float4 c = float4(sample(input, xy)); float dither = ((sample(table, xy).a) - 0.5)/256.0; return float4(clamp(c.rgb*ditherAlpha+dither,0.0,1.0), c.a); } )"); #ifdef MTK_SKIA_DITHER_EFFECT_DEBUG char ditherStringDbg[1024] = {0}; FILE* fp = fopen("/data/ditherStringDbg","rb"); if (fp) { fread(ditherStringDbg, 1, sizeof(ditherStringDbg), fp); int ret = fclose(fp); if (CC_UNLIKELY(ret != 0)) { ALOGE("%s(), fclose fail", __FUNCTION__); } } else { ALOGE("open file /data/ditherStringDbg failed"); } ALOGI("open file /data/ditherStringDbg"); ditherString = ditherStringDbg; #endif auto [ditherEffect, error] = SkRuntimeEffect::MakeForShader(ditherString); if (!ditherEffect) { ALOGE("%s(), RuntimeShader error: %s", __FUNCTION__, error.c_str()); return nullptr; } mDitherEffect = std::move(ditherEffect); SkRuntimeShaderBuilder ditherBuilder(mDitherEffect); ditherBuilder.child("input") = input; ditherBuilder.child("table") = ditherImage->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions({SkFilterMode::kNearest, SkMipmapMode::kNone})); ditherBuilder.uniform("ditherAlpha") = ditherAlpha; return ditherBuilder.makeShader(nullptr, false); } #endif } // namespace skia } // namespace renderengine } // namespace android