From 86e4310a14c802c499e8dfe63871bcca8e6706e9 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Wed, 23 Jul 2025 19:37:12 +0300 Subject: [PATCH] gl/wg engines: zero size blur dropshadow support - Implements support for zero size blur in drop shadow effects for both GL and WebGPU engines. When the blur sigma parameter is zero, the implementation now skips the blur processing entirely and uses the original image as the shadow source. Improving performance and avoiding unnecessary computations - EffectDropShadow example changed to reproduce zero sigma shadow https://github.com/thorvg/thorvg/issues/3602 --- examples/EffectDropShadow.cpp | 2 +- src/renderer/gl_engine/tvgGlEffect.cpp | 2 +- src/renderer/gl_engine/tvgGlRenderTask.cpp | 31 +++++++++++---------- src/renderer/wg_engine/tvgWgCompositor.cpp | 5 ++-- src/renderer/wg_engine/tvgWgRenderer.cpp | 8 +++--- src/renderer/wg_engine/tvgWgShaderTypes.cpp | 2 +- 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/examples/EffectDropShadow.cpp b/examples/EffectDropShadow.cpp index ede4c56a..446c0974 100644 --- a/examples/EffectDropShadow.cpp +++ b/examples/EffectDropShadow.cpp @@ -103,7 +103,7 @@ struct UserExample : tvgexam::Example scene2->push(tvg::SceneEffect::DropShadow, 65, 143, 222, (int)(255.0f * progress), 135.0, 10.0, 3.0, 100); scene3->push(tvg::SceneEffect::ClearAll); - scene3->push(tvg::SceneEffect::DropShadow, 0, 0, 0, 125, (double)(360.0f * progress), 20.0, 3.0, 100); + scene3->push(tvg::SceneEffect::DropShadow, 0, 0, 0, 125, (double)(360.0f * progress), 20.0, 0.0, 100); canvas->update(); diff --git a/src/renderer/gl_engine/tvgGlEffect.cpp b/src/renderer/gl_engine/tvgGlEffect.cpp index 1e8d5046..12ee22ba 100644 --- a/src/renderer/gl_engine/tvgGlEffect.cpp +++ b/src/renderer/gl_engine/tvgGlEffect.cpp @@ -141,7 +141,7 @@ void GlEffect::update(RenderEffectDropShadow* effect, const Matrix& transform) dropShadow->offset[1] = offset.y; dropShadow->extend = 2 * std::max(sigma * scale + std::abs(offset.x), sigma * scale + std::abs(offset.y)); effect->rd = dropShadow; - effect->valid = (dropShadow->extend > 0); + effect->valid = (dropShadow->extend >= 0); } diff --git a/src/renderer/gl_engine/tvgGlRenderTask.cpp b/src/renderer/gl_engine/tvgGlRenderTask.cpp index 9cd206e2..b6a505e1 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTask.cpp @@ -544,20 +544,23 @@ void GlEffectDropShadowTask::run() GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST)); GL_CHECK(glDisable(GL_BLEND)); - // horizontal blur - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstCopyFbo0->getResolveFboId())); - horzTask->setViewport(vp); - horzTask->addBindResource({ 0, dstCopyTexId1, horzSrcTextureLoc }); - horzTask->run(); - // vertical blur - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstCopyFbo1->getResolveFboId())); - vertTask->setViewport(vp); - vertTask->addBindResource({ 0, dstCopyTexId0, vertSrcTextureLoc }); - vertTask->run(); - // copy original image to intermediate buffer - GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, mDstFbo->getFboId())); - GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDstCopyFbo0->getResolveFboId())); - GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST)); + // when sigma is 0, no blur is applied, and the original image is used directly as the shadow. + if (!tvg::zero(effect->sigma)) { + // horizontal blur + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstCopyFbo0->getResolveFboId())); + horzTask->setViewport(vp); + horzTask->addBindResource({ 0, dstCopyTexId1, horzSrcTextureLoc }); + horzTask->run(); + // vertical blur + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstCopyFbo1->getResolveFboId())); + vertTask->setViewport(vp); + vertTask->addBindResource({ 0, dstCopyTexId0, vertSrcTextureLoc }); + vertTask->run(); + // copy original image to intermediate buffer + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, mDstFbo->getFboId())); + GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDstCopyFbo0->getResolveFboId())); + GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST)); + } // run drop shadow effect GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstFbo->getFboId())); GlRenderTask::run(); diff --git a/src/renderer/wg_engine/tvgWgCompositor.cpp b/src/renderer/wg_engine/tvgWgCompositor.cpp index c27d827d..65bb8212 100644 --- a/src/renderer/wg_engine/tvgWgCompositor.cpp +++ b/src/renderer/wg_engine/tvgWgCompositor.cpp @@ -875,8 +875,9 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderTarget* dst, const Ren auto aabb = compose->aabb; auto viewport = compose->rdViewport; - { // apply blur - copyTexture(&targetTemp1, dst, aabb); + copyTexture(&targetTemp1, dst, aabb); + // when sigma is 0, no blur is applied, and the original image is used directly as the shadow. + if (!tvg::zero(params->sigma)) { WgRenderTarget* sbuff = &targetTemp1; WgRenderTarget* dbuff = &targetTemp0; WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass drop shadow blur" }; diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index 12ffa7a9..36cccb7c 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -538,10 +538,10 @@ bool WgRenderer::region(RenderEffect* effect) } else if (effect->type == SceneEffect::DropShadow) { auto dropShadow = (RenderEffectDropShadow*)effect; auto renderData = (WgRenderDataEffectParams*)dropShadow->rd; - dropShadow->extend.min.x = -(renderData->extend + std::abs(renderData->offset.x)); - dropShadow->extend.max.x = +(renderData->extend + std::abs(renderData->offset.x)); - dropShadow->extend.min.y = -(renderData->extend + std::abs(renderData->offset.y)); - dropShadow->extend.max.y = +(renderData->extend + std::abs(renderData->offset.y)); + dropShadow->extend.min.x = -std::ceil(renderData->extend + std::abs(renderData->offset.x)); + dropShadow->extend.min.y = -std::ceil(renderData->extend + std::abs(renderData->offset.y)); + dropShadow->extend.max.x = +std::floor(renderData->extend + std::abs(renderData->offset.x)); + dropShadow->extend.max.y = +std::floor(renderData->extend + std::abs(renderData->offset.y)); return true; } return false; diff --git a/src/renderer/wg_engine/tvgWgShaderTypes.cpp b/src/renderer/wg_engine/tvgWgShaderTypes.cpp index 71f51c6b..05f67e15 100644 --- a/src/renderer/wg_engine/tvgWgShaderTypes.cpp +++ b/src/renderer/wg_engine/tvgWgShaderTypes.cpp @@ -247,7 +247,7 @@ bool WgShaderTypeEffectParams::update(RenderEffectDropShadow* dropShadow, const params[9] = offset.y; extend = params[2] * 2; // kernel - dropShadow->valid = (extend > 0); + dropShadow->valid = (extend >= 0); return dropShadow->valid; }