* Copyright (c) 2024 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_render.h"
#include "core/ge_effect_factory.h"
#include "ge_direct_draw_on_canvas_pass.h"
#include "ge_filter_composer.h"
#include "ge_hps_build_pass.h"
#include "ge_hps_effect_filter.h"
#include "ge_hps_upscale_pass.h"
#include "ge_log.h"
#include "ge_mesa_fusion_pass.h"
#include "ge_system_properties.h"
#include "ge_visual_effect_impl.h"
namespace OHOS {
namespace GraphicsEffectEngine {
#define PROPERTY_MESA_BLUR_ALL_ENABLED "persist.sys.graphic.kawaseDisable"
#ifdef GE_OHOS
std::atomic<bool> GERender::isMesablurAllEnable_(
GESystemProperties::ConvertToInt(
GESystemProperties::GetEventProperty(PROPERTY_MESA_BLUR_ALL_ENABLED).c_str(), 0) != 0);
#else
std::atomic<bool> GERender::isMesablurAllEnable_(false);
#endif
using namespace Rosen::Drawing;
GERender::GERender() {}
GERender::~GERender() {}
void GERender::DrawImageEffect(Drawing::Canvas& canvas, Drawing::GEVisualEffectContainer& veContainer,
const std::shared_ptr<Drawing::Image>& image, const Drawing::Rect& src, const Drawing::Rect& dst,
const Drawing::SamplingOptions& sampling)
{
if (!image) {
LOGE("GERender::DrawImageRect image is null");
return;
}
auto resImage = ApplyImageEffect(canvas, veContainer, {image, src, dst}, sampling);
if (!resImage) {
LOGE("GERender::DrawImageRect resImage is null");
return;
}
Drawing::Brush brush;
canvas.AttachBrush(brush);
canvas.DrawImageRect(*resImage, src, dst, Drawing::SamplingOptions());
canvas.DetachBrush();
}
std::shared_ptr<Drawing::Image> GERender::ApplyImageEffect(Drawing::Canvas& canvas,
Drawing::GEVisualEffectContainer& veContainer, const ShaderFilterEffectContext& context,
const Drawing::SamplingOptions& sampling)
{
if (!context.image) {
LOGE("GERender::ApplyImageEffect image is null");
return nullptr;
}
auto resImage = context.image;
for (auto& vef: veContainer.GetFilters()) {
ShaderFilterEffectContext innerContext {resImage, context.src, context.dst, context.geCacheProvider};
ProcessShaderFilter(canvas, vef, resImage, innerContext);
}
return resImage;
}
bool GERender::BeforeApplyShaderFilter(Drawing::Canvas& canvas,
const std::shared_ptr<Drawing::GEVisualEffect>& visualEffect, const ShaderFilterEffectContext& context,
std::shared_ptr<GEShaderFilter>& geShaderFilter)
{
if (visualEffect == nullptr) {
LOGD("GERender::BeforeApplyShaderFilter visualEffect is null");
return false;
}
auto ve = visualEffect->GetImpl();
geShaderFilter = GenerateShaderFilter(visualEffect);
if (geShaderFilter == nullptr) {
LOGD("GERender::BeforeApplyShaderFilter geShaderFilter is null");
return false;
}
geShaderFilter->SetSupportHeadroom(visualEffect->GetSupportHeadroom());
geShaderFilter->SetCache(ve->GetCache());
geShaderFilter->SetCacheProvider(context.geCacheProvider);
geShaderFilter->Preprocess(canvas, context.src, context.dst);
return true;
}
bool GERender::AfterApplyShaderFilter(Drawing::Canvas& canvas, const Drawing::GEVisualEffect& visualEffect,
const ShaderFilterEffectContext& context, const GEShaderFilter& geShaderFilter)
{
auto ve = visualEffect.GetImpl();
ve->SetCache(geShaderFilter.GetCache());
if (ve->GetFilterType() == Drawing::GEVisualEffectImpl::FilterType::GASIFY ||
ve->GetFilterType() == Drawing::GEVisualEffectImpl::FilterType::PARTICLE_ABLATION) {
isNeedExpansionFilter_ = true;
expansionRect_.SetLeft(context.src.GetLeft());
expansionRect_.SetTop(context.src.GetTop());
expansionRect_.SetRight(context.src.GetRight());
expansionRect_.SetBottom(context.src.GetBottom());
}
return true;
}
GERender::ApplyShaderFilterTarget GERender::DrawShaderFilter(Drawing::Canvas& canvas,
std::shared_ptr<Drawing::GEVisualEffect> visualEffect, Drawing::Brush& brush,
const ShaderFilterEffectContext& context)
{
std::shared_ptr<GEShaderFilter> geShaderFilter;
if (!BeforeApplyShaderFilter(canvas, visualEffect, context, geShaderFilter)) {
return ApplyShaderFilterTarget::Error;
}
bool status = geShaderFilter->DrawImage(canvas, context.image, context.src, context.dst, brush);
if (!status) {
return ApplyShaderFilterTarget::Error;
}
if (!AfterApplyShaderFilter(canvas, *visualEffect, context, *geShaderFilter)) {
return ApplyShaderFilterTarget::Error;
}
return ApplyShaderFilterTarget::DrawOnCanvas;
}
GERender::ApplyShaderFilterTarget GERender::ProcessShaderFilter(Drawing::Canvas& canvas,
std::shared_ptr<Drawing::GEVisualEffect> visualEffect, std::shared_ptr<Drawing::Image>& resImage,
const ShaderFilterEffectContext& context)
{
std::shared_ptr<GEShaderFilter> geShaderFilter;
if (!BeforeApplyShaderFilter(canvas, visualEffect, context, geShaderFilter)) {
return ApplyShaderFilterTarget::Error;
}
resImage = geShaderFilter->ProcessImage(canvas, resImage, context.src, context.dst);
if (!AfterApplyShaderFilter(canvas, *visualEffect, context, *geShaderFilter)) {
return ApplyShaderFilterTarget::Error;
}
return ApplyShaderFilterTarget::DrawOnImage;
}
static bool ComposeEffects(Drawing::Canvas& canvas,
const std::vector<std::shared_ptr<GEVisualEffect>>& visualEffects,
const GERender::HpsGEImageEffectContext& context, std::vector<GEFilterComposable>& composables)
{
if (visualEffects.empty()) {
return false;
}
GEFilterComposer composer;
composer.Add<GEHpsBuildPass>(canvas, context);
composer.Add<GEMesaFusionPass>();
composer.Add<GEHpsUpscalePass>();
composer.Add<GEDirectDrawOnCanvasPass>();
composables = GEFilterComposer::BuildComposables(visualEffects);
auto composerResult = composer.Run(composables);
if (!composerResult.anyPassChanged) {
return false;
}
return true;
}
GERender::ApplyHpsGEResult GERender::ApplyHpsGEImageEffect(Drawing::Canvas& canvas,
Drawing::GEVisualEffectContainer& veContainer, const HpsGEImageEffectContext& context,
std::shared_ptr<Drawing::Image>& outImage, Drawing::Brush& brush)
{
if (!context.image) {
LOGE("GERender::ApplyHpsGEImageEffect image is null");
return ApplyHpsGEResult::CanvasNotDrawnAndHpsNotApplied();
}
const auto& visualEffects = veContainer.GetFilters();
std::vector<GEFilterComposable> composables;
if (!ComposeEffects(canvas, visualEffects, context, composables)) {
return ApplyHpsGEResult::CanvasNotDrawnAndHpsNotApplied();
}
auto currentImage = context.image;
std::shared_ptr<Drawing::Image> resImage = nullptr;
bool appliedHpsBlur = false;
bool lastAppliedHpsBlur = false;
ApplyShaderFilterTarget applyTarget = ApplyShaderFilterTarget::Error;
for (auto& composable: composables) {
resImage = nullptr;
if (auto visualEffect = composable.GetEffect(); visualEffect != nullptr) {
ShaderFilterEffectContext geContext { currentImage, context.src, context.dst, context.geCacheProvider };
applyTarget = DispatchGEShaderFilter(canvas, brush, composable, visualEffect, geContext);
resImage = geContext.image;
} else if (auto hpsEffect = composable.GetHpsEffect(); hpsEffect != nullptr) {
HpsEffectFilter::HpsEffectContext hpsEffectContext = {
context.alpha, context.colorFilter, context.maskColor};
lastAppliedHpsBlur = hpsEffect->ApplyHpsEffect(canvas, currentImage, resImage, hpsEffectContext);
appliedHpsBlur |= lastAppliedHpsBlur;
applyTarget =
lastAppliedHpsBlur ? ApplyShaderFilterTarget::DrawOnCanvas : ApplyShaderFilterTarget::DrawOnImage;
} else {
LOGE("GERender::ApplyHpsGEImageEffect unhandled composable type");
}
if (resImage == nullptr) {
return ApplyHpsGEResult::CanvasNotDrawnAndHpsNotApplied();
}
currentImage = resImage;
}
outImage = resImage;
return { applyTarget == ApplyShaderFilterTarget::DrawOnCanvas, appliedHpsBlur };
}
GERender::ApplyShaderFilterTarget GERender::DispatchGEShaderFilter(Drawing::Canvas& canvas, Drawing::Brush& brush,
GEFilterComposable& composable, std::shared_ptr<Drawing::GEVisualEffect>& visualEffect,
ShaderFilterEffectContext& geContext)
{
ApplyShaderFilterTarget applyTarget;
if (DirectDrawOnCanvasFlag::IsDirectDrawOnCanvasEnabled(composable)) {
applyTarget = DrawShaderFilter(canvas, visualEffect, brush, geContext);
if (applyTarget == ApplyShaderFilterTarget::DrawOnCanvas) {
return applyTarget;
}
}
geContext.dst = geContext.src;
applyTarget = ProcessShaderFilter(canvas, visualEffect, geContext.image, geContext);
return applyTarget;
}
bool GERender::ApplyHpsImageEffect(Drawing::Canvas& canvas, Drawing::GEVisualEffectContainer& veContainer,
const HpsGEImageEffectContext& context, std::shared_ptr<Drawing::Image>& outImage)
{
auto hpsEffectFilter = std::make_shared<HpsEffectFilter>(canvas);
if (!context.image) {
LOGE("GERender::ApplyImageEffect image is null");
return false;
}
if (veContainer.GetFilters().empty()) {
return false;
}
if (hpsEffectFilter->HpsSupportEffectGE(veContainer)) {
for (auto vef : veContainer.GetFilters()) {
auto ve = vef->GetImpl();
hpsEffectFilter->GenerateVisualEffectFromGE(ve, context.src, context.dst, context.saturationForHPS,
context.brightnessForHPS, context.image);
}
HpsEffectFilter::HpsEffectContext hpsEffectContext = {context.alpha, context.colorFilter, context.maskColor};
return hpsEffectFilter->ApplyHpsEffect(canvas, context.image, outImage, hpsEffectContext);
}
return false;
}
std::shared_ptr<GEShaderFilter> GERender::GenerateShaderFilter(
const std::shared_ptr<Drawing::GEVisualEffect>& vef)
{
auto ve = vef->GetImpl();
LOGD("GERender::GenerateShaderFilter %{public}d", (int)ve->GetFilterType());
auto shaderFilter = GEEffectFactory::CreateFilter(ve);
if (shaderFilter) {
shaderFilter->SetShaderFilterCanvasinfo(vef->GetCanvasInfo());
shaderFilter->SetSupportHeadroom(vef->GetSupportHeadroom());
}
return shaderFilter;
}
std::vector<std::shared_ptr<GEShaderFilter>> GERender::GenerateShaderFilters(
const Drawing::GEVisualEffectContainer& veContainer)
{
LOGD("GERender::shaderFilters %{public}d", (int)veContainer.GetFilters().size());
std::vector<std::shared_ptr<GEShaderFilter>> shaderFilters;
for (auto vef : veContainer.GetFilters()) {
std::shared_ptr<GEShaderFilter> shaderFilter = GenerateShaderFilter(vef);
shaderFilters.push_back(shaderFilter);
}
return shaderFilters;
}
void GERender::DrawShaderEffect(Drawing::Canvas& canvas, Drawing::GEVisualEffectContainer& veContainer,
const Drawing::Rect& bounds)
{
LOGD("GERender::shaderEffects %{public}zu", veContainer.GetFilters().size());
std::vector<std::shared_ptr<GEShader>> shaderEffects;
for (auto vef : veContainer.GetFilters()) {
if (vef == nullptr) {
LOGD("GERender::DrawShaderEffect vef is null");
continue;
}
auto ve = vef->GetImpl();
std::shared_ptr<GEShader> geShaderEffect = GenerateShaderEffect(ve);
if (geShaderEffect == nullptr) {
LOGD("GERender::DrawShaderEffect shader is null");
continue;
}
geShaderEffect->SetShaderCanvasInfo(vef->GetCanvasInfo());
geShaderEffect->SetCache(ve->GetCache());
geShaderEffect->DrawShader(canvas, bounds);
ve->SetCache(geShaderEffect->GetCache());
}
}
std::shared_ptr<GEShader> GERender::GenerateShaderEffect(const std::shared_ptr<Drawing::GEVisualEffectImpl>& ve)
{
return GEEffectFactory::CreateShader(ve);
}
void GERender::SetMesablurAllEnabledByCCM(bool flag)
{
if (flag) {
isMesablurAllEnable_.store(true);
}
}
bool GERender::IsNeedExpansionFilter()
{
if (isNeedExpansionFilter_) {
isNeedExpansionFilter_ = false;
return true;
}
return false;
}
bool GERender::IsFrostedGlassFilter(Drawing::GEVisualEffectContainer& veContainer)
{
for (auto& vef: veContainer.GetFilters()) {
auto ve = vef->GetImpl();
if (ve->GetFilterType() == Drawing::GEVisualEffectImpl::FilterType::FROSTED_GLASS) {
return true;
}
}
return false;
}
}
}