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