* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ge_sdf_pixelmap_shader_shape.h"
#include "ge_log.h"
#include "ge_shader_diagnostics.h"
#include "ge_trace.h"
namespace OHOS {
namespace Rosen {
namespace Drawing {
constexpr float HALF = 0.5;
std::shared_ptr<ShaderEffect> GESDFPixelmapShaderShape::GenerateDrawingShader(float width, float height) const
{
GE_TRACE_NAME_FMT("GESDFPixelmapShaderShape::GenerateDrawingShader, Width: %g, Height: %g", width, height);
if (params_.image == nullptr) {
LOGE("GESDFPixelmapShaderShape::GenerateDrawingShader has empty image");
return nullptr;
}
std::shared_ptr<Drawing::RuntimeShaderBuilder> builder = GetSDFPixelmapShaderShapeBuilder();
if (!builder) {
LOGE("GESDFPixelmapShaderShape::GenerateDrawingShader has builder error");
return nullptr;
}
auto pixelmapShader = GeneratePixelmapShader();
if (!pixelmapShader) {
LOGE("GESDFPixelmapShaderShape::GenerateDrawingShader has empty shader");
return nullptr;
}
auto sdfPixelmapShapeShader = GenerateSDFShaderEffect(pixelmapShader, params_.image->GetImageInfo(), builder);
return sdfPixelmapShapeShader;
}
std::shared_ptr<ShaderEffect> GESDFPixelmapShaderShape::GenerateDrawingShaderHasNormal(float width, float height) const
{
GE_TRACE_NAME_FMT("GESDFPixelmapShaderShape::GenerateDrawingShaderHasNormal, Width: %g, Height: %g", width, height);
if (params_.image == nullptr) {
LOGE("GESDFPixelmapShaderShape::GenerateDrawingShaderHasNormal has empty image");
return nullptr;
}
std::shared_ptr<Drawing::RuntimeShaderBuilder> builder = GetSDFPixelmapNormalShaderShapeBuilder();
if (!builder) {
LOGE("GESDFPixelmapShaderShape::GenerateDrawingShaderHasNormal has builder error");
return nullptr;
}
auto pixelmapShader = GeneratePixelmapShader();
if (!pixelmapShader) {
LOGE("GESDFPixelmapShaderShape::GenerateDrawingShaderHasNormal has empty shader");
return nullptr;
}
auto sdfPixelmapShapeShader =
GenerateSDFNormalShaderEffect(pixelmapShader, params_.image->GetImageInfo(), width, height, builder);
return sdfPixelmapShapeShader;
}
std::shared_ptr<ShaderEffect> GESDFPixelmapShaderShape::GeneratePixelmapShader() const
{
Drawing::Matrix matrix;
return Drawing::ShaderEffect::CreateImageShader(*params_.image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP,
Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
}
std::shared_ptr<Drawing::RuntimeShaderBuilder> GESDFPixelmapShaderShape::GetSDFPixelmapShaderShapeBuilder() const
{
thread_local std::shared_ptr<Drawing::RuntimeShaderBuilder> sdfPixelmapShaderShapeBuilder = nullptr;
if (sdfPixelmapShaderShapeBuilder) {
return sdfPixelmapShaderShapeBuilder;
}
static constexpr char prog[] = R"(
uniform shader pixelmapShader;
uniform vec2 pixelmapSize;
vec4 SafeFetch(vec2 fragCoord) {
if (fragCoord.x < 0 || fragCoord.x >= pixelmapSize.x || fragCoord.y < 0 || fragCoord.y >= pixelmapSize.y) {
return vec4(0.5, 0.5, 0.0, 1);
}
return pixelmapShader.eval(fragCoord);
}
half4 main(vec2 fragCoord)
{
// SDF will be mapped from [0, 1] to [-63.5, 64]
vec4 pixelmapShape = SafeFetch(fragCoord);
return half4(pixelmapShape.xyz, pixelmapShape.a * 127.5 - 63.5);
}
)";
auto sdfPixelmapShaderBuilderEffect = GECreateRuntimeEffectForShader(prog);
if (!sdfPixelmapShaderBuilderEffect) {
LOGE("GESDFPixelmapShaderShape::GetSDFPixelmapShaderShapeBuilder effect error");
return nullptr;
}
sdfPixelmapShaderShapeBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(sdfPixelmapShaderBuilderEffect);
return sdfPixelmapShaderShapeBuilder;
}
std::shared_ptr<Drawing::RuntimeShaderBuilder> GESDFPixelmapShaderShape::GetSDFPixelmapNormalShaderShapeBuilder() const
{
thread_local std::shared_ptr<Drawing::RuntimeShaderBuilder> sdfPixelmapShaderShapeBuilder = nullptr;
if (sdfPixelmapShaderShapeBuilder) {
return sdfPixelmapShaderShapeBuilder;
}
static constexpr char prog[] = R"(
uniform shader pixelmapShader;
uniform vec2 pixelmapSize;
vec4 SafeFetch(vec2 fragCoord) {
if (fragCoord.x < 0 || fragCoord.x >= pixelmapSize.x || fragCoord.y < 0 || fragCoord.y >= pixelmapSize.y) {
return vec4(0.5, 0.5, 0.0, 1);
}
return pixelmapShader.eval(fragCoord);
}
uniform vec2 centerPos;
const float N_SCALE = 2048.0;
float EncodeDir(vec2 dir)
{
float xPos = floor(dir.x + N_SCALE);
float yPos = floor(dir.y + N_SCALE);
return xPos + (yPos / N_SCALE) / 2.0;
}
vec4 main(vec2 fragCoord)
{
// Gradient(rg channel) will be mapped from [0, 1] to [-1, 1]
// SDF(a channel) will be mapped from [0, 1] to [-63.5, 64]
vec4 pixelmapShape = SafeFetch(fragCoord);
return half4(pixelmapShape.xy * 2 - 1, EncodeDir(fragCoord - centerPos), pixelmapShape.a * 127.5 - 63.5);
}
)";
auto sdfPixelmapShaderBuilderEffect = GECreateRuntimeEffectForShader(prog);
if (!sdfPixelmapShaderBuilderEffect) {
LOGE("GESDFPixelmapShaderShape::GetSDFPixelmapNormalShaderShapeBuilder effect error");
return nullptr;
}
sdfPixelmapShaderShapeBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(sdfPixelmapShaderBuilderEffect);
return sdfPixelmapShaderShapeBuilder;
}
std::shared_ptr<ShaderEffect> GESDFPixelmapShaderShape::GenerateSDFShaderEffect(
std::shared_ptr<ShaderEffect> pixelmapShader, const Drawing::ImageInfo& pixelmapInfo,
std::shared_ptr<Drawing::RuntimeShaderBuilder> builder) const
{
if (!builder) {
LOGE("GESDFPixelmapShaderShape::GenerateSDFShaderEffect builder error");
return nullptr;
}
builder->SetChild("pixelmapShader", pixelmapShader);
builder->SetUniform("pixelmapSize", pixelmapInfo.GetWidth(), pixelmapInfo.GetHeight());
auto sdfPixelmapShapeShader = builder->MakeShader(nullptr, false);
if (!sdfPixelmapShapeShader) {
LOGE("GESDFPixelmapShaderShape::GenerateSDFShaderEffect shaderEffect error");
}
return sdfPixelmapShapeShader;
}
std::shared_ptr<ShaderEffect> GESDFPixelmapShaderShape::GenerateSDFNormalShaderEffect(
std::shared_ptr<ShaderEffect> pixelmapShader, const Drawing::ImageInfo& pixelmapInfo, float width, float height,
std::shared_ptr<Drawing::RuntimeShaderBuilder> builder) const
{
if (!builder) {
LOGE("GESDFPixelmapShaderShape::GenerateSDFNormalShaderEffect builder error");
return nullptr;
}
builder->SetChild("pixelmapShader", pixelmapShader);
builder->SetUniform("centerPos", width * HALF, height * HALF);
builder->SetUniform("pixelmapSize", pixelmapInfo.GetWidth(), pixelmapInfo.GetHeight());
auto sdfPixelmapShapeShader = builder->MakeShader(nullptr, false);
if (!sdfPixelmapShapeShader) {
LOGE("GESDFPixelmapShaderShape::GenerateSDFNormalShaderEffect shaderEffect error");
}
return sdfPixelmapShapeShader;
}
}
}
}