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 "ge_grey_shader_filter.h"
17 
18 #include "effect/runtime_effect.h"
19 #include "effect/runtime_shader_builder.h"
20 #include "ge_log.h"
21 
22 namespace OHOS {
23 namespace Rosen {
24 
GEGreyShaderFilter(const Drawing::GEGreyShaderFilterParams & params)25 GEGreyShaderFilter::GEGreyShaderFilter(const Drawing::GEGreyShaderFilterParams& params)
26     : greyCoef1_(params.greyCoef1), greyCoef2_(params.greyCoef2)
27 {
28     if (!InitGreyAdjustmentEffect()) {
29         LOGE("GEGreyShaderFilter::GEGreyShaderFilter failed to construct when initializing GreyAdjustmentEffect.");
30         return;
31     }
32 }
33 
34 static std::shared_ptr<Drawing::RuntimeEffect> g_greyAdjustEffect;
35 
ProcessImage(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> image,const Drawing::Rect & src,const Drawing::Rect & dst)36 std::shared_ptr<Drawing::Image> GEGreyShaderFilter::ProcessImage(Drawing::Canvas& canvas,
37     const std::shared_ptr<Drawing::Image> image, const Drawing::Rect& src, const Drawing::Rect& dst)
38 {
39     if (!image) {
40         LOGE("GEGreyShaderFilter::input image is null");
41         return image;
42     }
43 
44     if (!g_greyAdjustEffect) {
45         LOGE("GEGreyShaderFilter::DrawGreyAdjustment greyAdjustEffect is null");
46         return nullptr;
47     }
48     Drawing::RuntimeShaderBuilder builder(g_greyAdjustEffect);
49     Drawing::Matrix matrix;
50     auto imageShader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP,
51         Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
52 
53     builder.SetChild("imageShader", imageShader);
54     builder.SetUniform("coefficient1", greyCoef1_);
55     builder.SetUniform("coefficient2", greyCoef2_);
56     auto greyImage = builder.MakeImage(canvas.GetGPUContext().get(), nullptr, image->GetImageInfo(), false);
57     if (greyImage == nullptr) {
58         LOGE("DrawGreyAdjustment successful");
59         return image;
60     }
61     return greyImage;
62 };
63 
InitGreyAdjustmentEffect()64 bool GEGreyShaderFilter::InitGreyAdjustmentEffect()
65 {
66     if (g_greyAdjustEffect != nullptr) {
67         return true;
68     }
69 
70     static std::string GreyGradationString(R"(
71         uniform shader imageShader;
72         uniform float coefficient1;
73         uniform float coefficient2;
74 
75         float poww(float x, float y) {
76             return (x < 0) ? -pow(-x, y) : pow(x, y);
77         }
78 
79         float calculateT_y(float rgb) {
80             if (rgb > 127.5) { rgb = 255 - rgb; }
81             float b = 38.0;
82             float c = 45.0;
83             float d = 127.5;
84             float A = 106.5;    // 3 * b - 3 * c + d;
85             float B = -93;      // 3 * (c - 2 * b);
86             float C = 114;      // 3 * b;
87             float p = 0.816240163988;                   // (3 * A * C - pow(B, 2)) / (3 * pow(A, 2));
88             float q = -rgb / 106.5 + 0.262253485943;    // -rgb/A - B*C/(3*pow(A,2)) + 2*pow(B,3)/(27*pow(A,3))
89             float s1 = -(q / 2.0);
90             float s2 = sqrt(pow(s1, 2) + pow(p / 3, 3));
91             return poww((s1 + s2), 1.0 / 3) + poww((s1 - s2), 1.0 / 3) - (B / (3 * A));
92         }
93 
94         float calculateGreyAdjustY(float rgb) {
95             float t_r = calculateT_y(rgb);
96             return (rgb < 127.5) ? (rgb + coefficient1 * pow((1 - t_r), 3)) :
97                 (rgb - coefficient2 * pow((1 - t_r), 3));
98         }
99 
100         half4 main(float2 coord) {
101             vec3 color = vec3(imageShader.eval(coord).r, imageShader.eval(coord).g, imageShader.eval(coord).b);
102             float Y = (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) * 255;
103             float U = (-0.147 * color.r - 0.289 * color.g + 0.436 * color.b) * 255;
104             float V = (0.615 * color.r - 0.515 * color.g - 0.100 * color.b) * 255;
105             Y = calculateGreyAdjustY(Y);
106             color.r = (Y + 1.14 * V) / 255.0;
107             color.g = (Y - 0.39 * U - 0.58 * V) / 255.0;
108             color.b = (Y + 2.03 * U) / 255.0;
109 
110             return vec4(color, 1.0);
111         }
112     )");
113     g_greyAdjustEffect = Drawing::RuntimeEffect::CreateForShader(GreyGradationString);
114     if (g_greyAdjustEffect == nullptr) {
115         LOGE("GEGreyShaderFilter::InitGreyAdjustmentEffect blurEffect create failed");
116         return false;
117     }
118 
119     return true;
120 }
121 
122 } // namespace Rosen
123 } // namespace OHOS
124