diff --git a/src/renderer/gl_engine/tvgGlCommon.h b/src/renderer/gl_engine/tvgGlCommon.h index 990911e1..b9f6f0c5 100644 --- a/src/renderer/gl_engine/tvgGlCommon.h +++ b/src/renderer/gl_engine/tvgGlCommon.h @@ -200,4 +200,12 @@ struct GlCompositor : RenderCompositor GlCompositor(const RenderRegion& box) : bbox(box) {} }; +#define GL_GAUSSIAN_MAX_LEVEL 3 +struct GlGaussianBlur { + int level{}; + float sigma{}; + float scale{}; + float extend{}; +}; + #endif /* _TVG_GL_COMMON_H_ */ diff --git a/src/renderer/gl_engine/tvgGlRenderPass.h b/src/renderer/gl_engine/tvgGlRenderPass.h index 96890f06..255c6cc0 100644 --- a/src/renderer/gl_engine/tvgGlRenderPass.h +++ b/src/renderer/gl_engine/tvgGlRenderPass.h @@ -63,9 +63,7 @@ public: auto task = new T(program, targetFbo, mFbo, std::move(mTasks)); - const auto& vp = mFbo->getViewport(); - - task->setRenderSize(static_cast(vp.w), static_cast(vp.h)); + task->setRenderSize(getFboWidth(), getFboHeight()); return task; } diff --git a/src/renderer/gl_engine/tvgGlRenderTarget.cpp b/src/renderer/gl_engine/tvgGlRenderTarget.cpp index b0157ff3..ebad8982 100644 --- a/src/renderer/gl_engine/tvgGlRenderTarget.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTarget.cpp @@ -99,34 +99,20 @@ uint32_t alignPow2(uint32_t value) return ret; } -GlRenderTarget* GlRenderTargetPool::getRenderTarget(const RenderRegion& vp, GLuint resolveId) +GlRenderTarget* GlRenderTargetPool::getRenderTarget(GLuint resolveId) { - uint32_t width = static_cast(vp.w); - uint32_t height = static_cast(vp.h); - - // pow2 align width and height - if (width >= mMaxWidth) width = mMaxWidth; - else width = alignPow2(width); - - if (width >= mMaxWidth) width = mMaxWidth; - - if (height >= mMaxHeight) height = mMaxHeight; - else height = alignPow2(height); - - if (height >= mMaxHeight) height = mMaxHeight; - for (uint32_t i = 0; i < mPool.count; i++) { auto rt = mPool[i]; - if (rt->getWidth() == width && rt->getHeight() == height) { - rt->setViewport(vp); + if (rt->getWidth() == mMaxWidth && rt->getHeight() == mMaxHeight) { + rt->setViewport({0, 0, (int32_t)mMaxWidth, (int32_t)mMaxHeight}); return rt; } } - auto rt = new GlRenderTarget(width, height); + auto rt = new GlRenderTarget(mMaxWidth, mMaxHeight); rt->init(resolveId); - rt->setViewport(vp); + rt->setViewport({0, 0, (int32_t)mMaxWidth, (int32_t)mMaxHeight}); mPool.push(rt); return rt; } diff --git a/src/renderer/gl_engine/tvgGlRenderTarget.h b/src/renderer/gl_engine/tvgGlRenderTarget.h index c1ff6d50..203caf24 100644 --- a/src/renderer/gl_engine/tvgGlRenderTarget.h +++ b/src/renderer/gl_engine/tvgGlRenderTarget.h @@ -61,7 +61,7 @@ public: GlRenderTargetPool(uint32_t maxWidth, uint32_t maxHeight); ~GlRenderTargetPool(); - GlRenderTarget* getRenderTarget(const RenderRegion& vp, GLuint resolveId = 0); + GlRenderTarget* getRenderTarget(GLuint resolveId = 0); private: uint32_t mMaxWidth = 0; uint32_t mMaxHeight = 0; diff --git a/src/renderer/gl_engine/tvgGlRenderTask.cpp b/src/renderer/gl_engine/tvgGlRenderTask.cpp index 6e4f91bc..d28a06c1 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTask.cpp @@ -379,3 +379,45 @@ void GlComplexBlendTask::normalizeDrawDepth(int32_t maxDepth) mStencilTask->normalizeDrawDepth(maxDepth); GlRenderTask::normalizeDrawDepth(maxDepth); } + +void GlGaussianBlurTask::run() { + GL_CHECK(glDisable(GL_BLEND)); + uint32_t width = targetDest->getWidth(); + uint32_t height = targetDest->getHeight(); + + GL_CHECK(glScissor(0, 0, width, height)); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, targetDest->getFboId())); + GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetTemp0->getResolveFboId())); + GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST)); + GL_CHECK(glScissor(0, 0, width, height)); + GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, targetTemp0->getResolveFboId())); + GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetTemp1->getResolveFboId())); + GL_CHECK(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST)); + + auto blur = (RenderEffectGaussianBlur*)mEffect; + int32_t widthTemp = (int32_t)targetTemp0->getWidth(); + int32_t heightTemp = (int32_t)targetTemp0->getHeight(); + GL_CHECK(glViewport(0, 0, widthTemp, heightTemp)); + // horizontal + if (blur->direction == 1) { + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, targetDest->getFboId())); + GL_CHECK(glViewport(0, 0, widthTemp, heightTemp)); + gaussTaskHorz->addBindResource(GlBindingResource{0, targetTemp0->getColorTexture(), gaussTaskHorz->getProgram()->getUniformLocation("uSrcTexture")}); + gaussTaskHorz->run(); + } // vertical + else if (blur->direction == 2) { + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, targetDest->getFboId())); + gaussTaskVert->addBindResource(GlBindingResource{0, targetTemp0->getColorTexture(), gaussTaskVert->getProgram()->getUniformLocation("uSrcTexture")}); + gaussTaskVert->run(); + } // both + else { + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, targetTemp1->getResolveFboId())); + GL_CHECK(glViewport(0, 0, widthTemp, heightTemp)); + gaussTaskVert->addBindResource(GlBindingResource{0, targetTemp0->getColorTexture(), gaussTaskVert->getProgram()->getUniformLocation("uSrcTexture")}); + gaussTaskVert->run(); + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, targetDest->getFboId())); + gaussTaskHorz->addBindResource(GlBindingResource{0, targetTemp1->getColorTexture(), gaussTaskHorz->getProgram()->getUniformLocation("uSrcTexture")}); + gaussTaskHorz->run(); + } + GL_CHECK(glEnable(GL_BLEND)); +}; diff --git a/src/renderer/gl_engine/tvgGlRenderTask.h b/src/renderer/gl_engine/tvgGlRenderTask.h index 5ca99843..bf993852 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.h +++ b/src/renderer/gl_engine/tvgGlRenderTask.h @@ -219,4 +219,21 @@ private: GlComposeTask* mComposeTask; }; +class GlGaussianBlurTask: public GlRenderTask +{ +public: + GlGaussianBlurTask(const RenderEffect* effect): GlRenderTask(nullptr), mEffect(effect){}; + ~GlGaussianBlurTask() override{ delete gaussTaskVert; delete gaussTaskHorz; }; + + GlRenderTask* gaussTaskVert{}; + GlRenderTask* gaussTaskHorz{}; + GlRenderTarget* targetDest{}; + GlRenderTarget* targetTemp0{}; + GlRenderTarget* targetTemp1{}; + + void run() override; +protected: + const RenderEffect* mEffect; +}; + #endif /* _TVG_GL_RENDER_TASK_H_ */ diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index ff8a0285..af3142a0 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -140,6 +140,10 @@ void GlRenderer::initShaders() mPrograms.push(new GlProgram(MASK_VERT_SHADER, SOFT_LIGHT_BLEND_FRAG)); mPrograms.push(new GlProgram(MASK_VERT_SHADER, DIFFERENCE_BLEND_FRAG)); mPrograms.push(new GlProgram(MASK_VERT_SHADER, EXCLUSION_BLEND_FRAG)); + + // effects + mPrograms.push(new GlProgram(EFFECT_VERT, GAUSSIAN_VERTICAL)); + mPrograms.push(new GlProgram(EFFECT_VERT, GAUSSIAN_HORIZONTAL)); } @@ -157,11 +161,6 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const RenderColor& c, RenderUpdat bbox.intersect(vp); } - auto x = bbox.x - vp.x; - auto y = bbox.y - vp.y; - auto w = bbox.w; - auto h = bbox.h; - GlRenderTask* task = nullptr; if (mBlendMethod != BlendMethod::Normal && !complexBlend) task = new GlSimpleBlendTask(mBlendMethod, mPrograms[RT_Color]); else task = new GlRenderTask(mPrograms[RT_Color]); @@ -173,7 +172,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const RenderColor& c, RenderUpdat return; } - task->setViewport({x, vp.h - y - h, w, h}); + task->setViewport({bbox.x, vp.h - bbox.y - bbox.h, bbox.w, bbox.h}); GlRenderTask* stencilTask = nullptr; @@ -270,10 +269,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla if (complexBlend) vp = currentPass()->getViewport(); - auto x = bbox.x - vp.x; - auto y = bbox.y - vp.y; - - task->setViewport({x, vp.h - y - bbox.h, bbox.w, bbox.h}); + task->setViewport({bbox.x, vp.h - bbox.y - bbox.h, bbox.w, bbox.h}); GlRenderTask* stencilTask = nullptr; GlStencilMode stencilMode = sdata.geometry.getStencilMode(flag); @@ -427,39 +423,19 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla void GlRenderer::drawClip(Array& clips) { - Array identityVertex(4 * 2); - float left = -1.f; - float top = 1.f; - float right = 1.f; - float bottom = -1.f; + // draw clip + float vertices[8] = { + -1.0f, +1.0f, // left top point + -1.0f, -1.0f, // left bottom point + +1.0f, +1.0f, // right top point + +1.0f, -1.0f // right bottom point + }; + uint32_t indices[6] = { 0, 1, 2, 2, 1, 3 }; + float mat4[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; - identityVertex.push(left); - identityVertex.push(top); - identityVertex.push(left); - identityVertex.push(bottom); - identityVertex.push(right); - identityVertex.push(top); - identityVertex.push(right); - identityVertex.push(bottom); - - Array identityIndex(6); - identityIndex.push(0); - identityIndex.push(1); - identityIndex.push(2); - identityIndex.push(2); - identityIndex.push(1); - identityIndex.push(3); - - float mat4[16]; - memset(mat4, 0, sizeof(float) * 16); - mat4[0] = 1.f; - mat4[5] = 1.f; - mat4[10] = 1.f; - mat4[15] = 1.f; - - auto identityVertexOffset = mGpuBuffer.push(identityVertex.data, 8 * sizeof(float)); - auto identityIndexOffset = mGpuBuffer.pushIndex(identityIndex.data, 6 * sizeof(uint32_t)); - auto mat4Offset = mGpuBuffer.push(mat4, 16 * sizeof(float), true); + auto identityVertexOffset = mGpuBuffer.push(vertices, sizeof(vertices)); + auto identityIndexOffset = mGpuBuffer.pushIndex(indices, sizeof(indices)); + auto mat4Offset = mGpuBuffer.push(mat4, sizeof(mat4), true); Array clipDepths(clips.count); clipDepths.count = clips.count; @@ -484,10 +460,7 @@ void GlRenderer::drawClip(Array& clips) bbox.intersect(vp); - auto x = bbox.x - vp.x; - auto y = bbox.y - vp.y; - - clipTask->setViewport({x, vp.h - y - bbox.h, bbox.w, bbox.h}); + clipTask->setViewport({bbox.x, vp.h - bbox.y - bbox.h, bbox.w, bbox.h}); float matrix44[16]; currentPass()->getMatrix(matrix44, sdata->geometry.matrix); @@ -527,7 +500,7 @@ bool GlRenderer::beginComplexBlending(const RenderRegion& vp, RenderRegion bound if (mBlendPool.empty()) mBlendPool.push(new GlRenderTargetPool(surface.w, surface.h)); - auto blendFbo = mBlendPool[0]->getRenderTarget(bounds); + auto blendFbo = mBlendPool[0]->getRenderTarget(); mRenderPassStack.push(new GlRenderPass(blendFbo)); @@ -545,19 +518,9 @@ void GlRenderer::endBlendingCompose(GlRenderTask* stencilTask, const Matrix& mat const auto& vp = blendPass->getViewport(); if (mBlendPool.count < 2) mBlendPool.push(new GlRenderTargetPool(surface.w, surface.h)); - auto dstCopyFbo = mBlendPool[1]->getRenderTarget(vp); - - { - const auto& passVp = currentPass()->getViewport(); - - auto x = vp.x; - auto y = vp.y; - auto w = vp.w; - auto h = vp.h; - - stencilTask->setViewport({x, passVp.h - y - h, w, h}); - } + auto dstCopyFbo = mBlendPool[1]->getRenderTarget(); + stencilTask->setViewport(currentPass()->getViewport()); stencilTask->setDrawDepth(currentPass()->nextDrawDepth()); { @@ -616,75 +579,21 @@ void GlRenderer::prepareBlitTask(GlBlitTask* task) void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint32_t cmpWidth, uint32_t cmpHeight) { - // we use 1:1 blit mapping since compositor fbo is same size as root fbo - Array vertices(4 * 4); + float vertices[16] = { + -1.0f, +1.0f, 0.0f, 1.0f, // left top point + -1.0f, -1.0f, 0.0f, 0.0f, // left bottom point + +1.0f, +1.0f, 1.0f, 1.0f, // right top point + +1.0f, -1.0f, 1.0f, 0.0f // right bottom point + }; + uint32_t indices[6] = { 0, 1, 2, 2, 1, 3 }; - const auto& passVp = currentPass()->getViewport(); - - auto taskVp = vp; - taskVp.intersect(passVp); - - auto x = taskVp.x - passVp.x; - auto y = taskVp.y - passVp.y; - auto w = taskVp.w; - auto h = taskVp.h; - - float rw = static_cast(passVp.w); - float rh = static_cast(passVp.h); - - float l = static_cast(x); - float t = static_cast(rh - y); - float r = static_cast(x + w); - float b = static_cast(rh - y - h); - - // map vp ltrp to -1:1 - float left = (l / rw) * 2.f - 1.f; - float top = (t / rh) * 2.f - 1.f; - float right = (r / rw) * 2.f - 1.f; - float bottom = (b / rh) * 2.f - 1.f; - - float uw = static_cast(w) / static_cast(cmpWidth); - float uh = static_cast(h) / static_cast(cmpHeight); - - // left top point - vertices.push(left); - vertices.push(top); - vertices.push(0.f); - vertices.push(uh); - // left bottom point - vertices.push(left); - vertices.push(bottom); - vertices.push(0.f); - vertices.push(0.f); - // right top point - vertices.push(right); - vertices.push(top); - vertices.push(uw); - vertices.push(uh); - // right bottom point - vertices.push(right); - vertices.push(bottom); - vertices.push(uw); - vertices.push(0.f); - - Array indices(6); - - indices.push(0); - indices.push(1); - indices.push(2); - indices.push(2); - indices.push(1); - indices.push(3); - - uint32_t vertexOffset = mGpuBuffer.push(vertices.data, vertices.count * sizeof(float)); - uint32_t indexOffset = mGpuBuffer.pushIndex(indices.data, indices.count * sizeof(uint32_t)); + uint32_t vertexOffset = mGpuBuffer.push(vertices, sizeof(vertices)); + uint32_t indexOffset = mGpuBuffer.pushIndex(indices, sizeof(indices)); task->addVertexLayout(GlVertexLayout{0, 2, 4 * sizeof(float), vertexOffset}); task->addVertexLayout(GlVertexLayout{1, 2, 4 * sizeof(float), vertexOffset + 2 * sizeof(float)}); - - task->setDrawRange(indexOffset, indices.count); - - task->setViewport({x, static_cast((passVp.h - y - h)), w, h}); + task->setDrawRange(indexOffset, 6); + task->setViewport(vp); } @@ -715,16 +624,18 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp) } if (program && !selfPass->isEmpty() && !maskPass->isEmpty()) { + auto vp = currentPass()->getViewport(); + auto bbox = glCmp->bbox; auto prev_task = maskPass->endRenderPass(nullptr, currentPass()->getFboId()); prev_task->setDrawDepth(currentPass()->nextDrawDepth()); - prev_task->setRenderSize(static_cast(glCmp->bbox.w), static_cast(glCmp->bbox.h)); - prev_task->setViewport(glCmp->bbox); + prev_task->setRenderSize(maskPass->getFboWidth(), maskPass->getFboHeight()); + prev_task->setViewport({bbox.x, vp.h - bbox.y - bbox.h, bbox.w, bbox.h}); auto compose_task = selfPass->endRenderPass(program, currentPass()->getFboId()); - compose_task->setRenderSize(static_cast(glCmp->bbox.w), static_cast(glCmp->bbox.h)); + compose_task->setRenderSize(maskPass->getFboWidth(), maskPass->getFboHeight()); compose_task->setPrevTask(prev_task); - - prepareCmpTask(compose_task, glCmp->bbox, selfPass->getFboWidth(), selfPass->getFboHeight()); + + prepareCmpTask(compose_task, {bbox.x, vp.h - bbox.y - bbox.h, bbox.w, bbox.h}, selfPass->getFboWidth(), selfPass->getFboHeight()); compose_task->addBindResource(GlBindingResource{0, selfPass->getTextureId(), program->getUniformLocation("uSrcTexture")}); compose_task->addBindResource(GlBindingResource{1, maskPass->getTextureId(), program->getUniformLocation("uMaskTexture")}); @@ -742,9 +653,10 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp) mRenderPassStack.pop(); if (!renderPass->isEmpty()) { + RenderRegion vp{0, 0, (int32_t)renderPass->getFboWidth(), (int32_t)renderPass->getFboHeight()}; auto task = renderPass->endRenderPass(mPrograms[RT_Image], currentPass()->getFboId()); - task->setRenderSize(static_cast(glCmp->bbox.w), static_cast(glCmp->bbox.h)); - prepareCmpTask(task, glCmp->bbox, renderPass->getFboWidth(), renderPass->getFboHeight()); + task->setRenderSize(renderPass->getFboWidth(), renderPass->getFboHeight()); + prepareCmpTask(task, vp, renderPass->getFboWidth(), renderPass->getFboHeight()); task->setDrawDepth(currentPass()->nextDrawDepth()); // matrix buffer @@ -811,6 +723,13 @@ bool GlRenderer::target(void* context, int32_t id, uint32_t w, uint32_t h) mRootTarget = GlRenderTarget(surface.w, surface.h); mRootTarget.setViewport({0, 0, static_cast(surface.w), static_cast(surface.h)}); mRootTarget.init(mTargetFboId); + mTempTarget0 = GlRenderTarget(surface.w, surface.h); + mTempTarget0.setViewport({0, 0, static_cast(surface.w), static_cast(surface.h)}); + mTempTarget0.init(mTargetFboId); + mTempTarget1 = GlRenderTarget(surface.w, surface.h); + mTempTarget1.setViewport({0, 0, static_cast(surface.w), static_cast(surface.h)}); + mTempTarget1.init(mTargetFboId); + return true; } @@ -914,7 +833,7 @@ bool GlRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_ auto glCmp = static_cast(cmp); if (glCmp->bbox.w > 0 && glCmp->bbox.h > 0) { - auto renderTarget = mComposePool[index]->getRenderTarget(glCmp->bbox); + auto renderTarget = mComposePool[index]->getRenderTarget(); mRenderPassStack.push(new GlRenderPass(renderTarget)); } else { // empty render pass @@ -944,29 +863,99 @@ bool GlRenderer::endComposite(RenderCompositor* cmp) } -void GlRenderer::prepare(TVG_UNUSED RenderEffect* effect, TVG_UNUSED const Matrix& transform) +void GlRenderer::effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform) { - //TODO: prepare the effect + GlGaussianBlur* blur = (GlGaussianBlur*)effect->rd; + if (!blur) blur = tvg::malloc(sizeof(GlGaussianBlur)); + blur->sigma = effect->sigma; + blur->scale = std::sqrt(transform.e11 * transform.e11 + transform.e12 * transform.e12); + blur->extend = 2 * blur->sigma * blur->scale; + blur->level = int(GL_GAUSSIAN_MAX_LEVEL * ((effect->quality - 1) * 0.01f)) + 1; + effect->rd = blur; } -bool GlRenderer::region(TVG_UNUSED RenderEffect* effect) +bool GlRenderer::effectGaussianBlurRegion(RenderEffectGaussianBlur* effect) { - //TODO: Return if the current post effect requires the region expansion + auto gaussianBlur = (GlGaussianBlur*)effect->rd; + if (effect->direction != 2) { + effect->extend.x = -gaussianBlur->extend * 2; + effect->extend.w = +gaussianBlur->extend * 4; + } + if (effect->direction != 1) { + effect->extend.y = -gaussianBlur->extend * 2; + effect->extend.h = +gaussianBlur->extend * 4; + } + return true; +}; + + +void GlRenderer::prepare(RenderEffect* effect, const Matrix& transform) +{ + switch (effect->type) { + case SceneEffect::GaussianBlur: effectGaussianBlurUpdate(static_cast(effect), transform); break; + default: break; + } + effect->valid = true; +} + + +bool GlRenderer::region(RenderEffect* effect) +{ + switch (effect->type) { + case SceneEffect::GaussianBlur: return effectGaussianBlurRegion(static_cast(effect)); + default: return false; + } return false; } -bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, TVG_UNUSED const RenderEffect* effect, TVG_UNUSED bool direct) +bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* effect, TVG_UNUSED bool direct) { - TVGLOG("GL_ENGINE", "SceneEffect(%d) is not supported", (int)effect->type); + auto pass = currentPass(); + auto vp = pass->getViewport(); + auto bbox = ((GlCompositor*)cmp)->bbox; + + const float vdata[] = {-1.0f, +1.0f, +1.0f, +1.0f, +1.0f, -1.0f, -1.0f, -1.0f}; + const uint32_t idata[] = { 0, 1, 2, 0, 2, 3 }; + auto voffset = mGpuBuffer.push((void*)vdata, sizeof(vdata)); + auto ioffset = mGpuBuffer.pushIndex((void*)idata, sizeof(idata)); + + GlProgram* programHorz = mPrograms[RT_GaussianHorz]; + GlProgram* programVert = mPrograms[RT_GaussianVert]; + + if (effect->type == SceneEffect::GaussianBlur) { + GlGaussianBlur* blur = (GlGaussianBlur*)(effect->rd); + auto blurOffset = mGpuBuffer.push(blur, sizeof(GlGaussianBlur), true); + auto task = new GlGaussianBlurTask(effect); + task->targetDest = pass->getFbo(); + task->targetTemp0 = &mTempTarget0; + task->targetTemp1 = &mTempTarget1; + // horizontal blur task + task->gaussTaskHorz = new GlRenderTask(programHorz); + task->gaussTaskHorz->setViewport({bbox.x, vp.h - bbox.y - bbox.h, bbox.w, bbox.h}); + task->gaussTaskHorz->addBindResource(GlBindingResource{0, programHorz->getUniformBlockIndex("Gaussian"), mGpuBuffer.getBufferId(), blurOffset, sizeof(GlGaussianBlur)}); + task->gaussTaskHorz->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset}); + task->gaussTaskHorz->setDrawRange(ioffset, 6); + // vertical blur task + task->gaussTaskVert = new GlRenderTask(programVert); + task->gaussTaskVert->setViewport({bbox.x, vp.h - bbox.y - bbox.h, bbox.w, bbox.h}); + task->gaussTaskVert->addBindResource(GlBindingResource{0, programVert->getUniformBlockIndex("Gaussian"), mGpuBuffer.getBufferId(), blurOffset, sizeof(GlGaussianBlur)}); + task->gaussTaskVert->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset}); + task->gaussTaskVert->setDrawRange(ioffset, 6); + task->setViewport({bbox.x, vp.h - bbox.y - bbox.h, bbox.w, bbox.h}); + pass->addRenderTask(task); + return true; + }; + return false; } -void GlRenderer::dispose(TVG_UNUSED RenderEffect* effect) +void GlRenderer::dispose(RenderEffect* effect) { - //TODO: dispose the effect + tvg::free(effect->rd); + effect->rd = nullptr; } @@ -1009,10 +998,6 @@ bool GlRenderer::renderImage(void* data) if (bbox.w <= 0 || bbox.h <= 0) return true; - auto x = bbox.x - vp.x; - auto y = bbox.y - vp.y; - - int32_t drawDepth = currentPass()->nextDrawDepth(); if (!sdata->clips.empty()) drawClip(sdata->clips); @@ -1055,7 +1040,7 @@ bool GlRenderer::renderImage(void* data) // texture id task->addBindResource(GlBindingResource{0, sdata->texId, task->getProgram()->getUniformLocation("uTexture")}); - task->setViewport({x, vp.h - y - bbox.h, bbox.w, bbox.h}); + task->setViewport(bbox); currentPass()->addRenderTask(task); diff --git a/src/renderer/gl_engine/tvgGlRenderer.h b/src/renderer/gl_engine/tvgGlRenderer.h index edcc16af..1fc3dd9e 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.h +++ b/src/renderer/gl_engine/tvgGlRenderer.h @@ -60,6 +60,9 @@ public: RT_DifferenceBlend, RT_ExclusionBlend, + RT_GaussianVert, + RT_GaussianHorz, + RT_None, }; @@ -116,6 +119,9 @@ private: void prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint32_t cmpWidth, uint32_t cmpHeight); void endRenderPass(RenderCompositor* cmp); + void effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform); + bool effectGaussianBlurRegion(RenderEffectGaussianBlur* effect); + void flush(); void clearDisposes(); void currentContext(); @@ -126,6 +132,8 @@ private: RenderRegion mViewport; GlStageBuffer mGpuBuffer; GlRenderTarget mRootTarget; + GlRenderTarget mTempTarget0; + GlRenderTarget mTempTarget1; Array mPrograms; Array mComposePool; Array mBlendPool; diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.cpp b/src/renderer/gl_engine/tvgGlShaderSrc.cpp index e123cfb6..a0f8b887 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.cpp +++ b/src/renderer/gl_engine/tvgGlShaderSrc.cpp @@ -737,3 +737,86 @@ const char* EXCLUSION_BLEND_FRAG = COMPLEX_BLEND_HEADER R"( FragColor = dstColor + srcColor - (2.0 * dstColor * srcColor); } )"; + +const char* EFFECT_VERT = R"( +layout(location = 0) in vec2 aLocation; +out vec2 vUV; + +void main() +{ + vUV = aLocation * 0.5 + 0.5; + gl_Position = vec4(aLocation, 0.0, 1.0); +} +)"; + +const char* GAUSSIAN_VERTICAL = R"( +uniform sampler2D uSrcTexture; +layout(std140) uniform Gaussian { + int level; + float sigma; + float scale; + float extend; +} uGaussian; + +in vec2 vUV; +out vec4 FragColor; + +float gaussian(float x, float sigma) { + float exponent = -x * x / (2.0 * sigma * sigma); + return exp(exponent) / (sqrt(2.0 * 3.141592) * sigma); +} + +void main() +{ + vec2 texelSize = 1.0 / vec2(textureSize(uSrcTexture, 0)); + vec4 colorSum = vec4(0.0); + float sigma = uGaussian.sigma * uGaussian.scale; + float weightSum = 0.0; + int radius = int(uGaussian.extend); + + for (int y = -radius; y <= radius; ++y) { + float weight = gaussian(float(y), sigma); + vec2 offset = vec2(0.0, float(y) * texelSize.y); + colorSum += texture(uSrcTexture, vUV + offset) * weight; + weightSum += weight; + } + + FragColor = colorSum / weightSum; +} +)"; + +const char* GAUSSIAN_HORIZONTAL = R"( +uniform sampler2D uSrcTexture; +layout(std140) uniform Gaussian { + int level; + float sigma; + float scale; + float extend; +} uGaussian; + +in vec2 vUV; +out vec4 FragColor; + +float gaussian(float x, float sigma) { + float exponent = -x * x / (2.0 * sigma * sigma); + return exp(exponent) / (sqrt(2.0 * 3.141592) * sigma); +} + +void main() +{ + vec2 texelSize = 1.0 / vec2(textureSize(uSrcTexture, 0)); + vec4 colorSum = vec4(0.0); + float sigma = uGaussian.sigma * uGaussian.scale; + float weightSum = 0.0; + int radius = int(uGaussian.extend); + + for (int y = -radius; y <= radius; ++y) { + float weight = gaussian(float(y), sigma); + vec2 offset = vec2(float(y) * texelSize.x, 0.0); + colorSum += texture(uSrcTexture, vUV + offset) * weight; + weightSum += weight; + } + + FragColor = colorSum / weightSum; +} +)"; diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.h b/src/renderer/gl_engine/tvgGlShaderSrc.h index dd81363a..d7c7e7c7 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.h +++ b/src/renderer/gl_engine/tvgGlShaderSrc.h @@ -54,5 +54,8 @@ extern const char* HARD_LIGHT_BLEND_FRAG; extern const char* SOFT_LIGHT_BLEND_FRAG; extern const char* DIFFERENCE_BLEND_FRAG; extern const char* EXCLUSION_BLEND_FRAG; +extern const char* EFFECT_VERT; +extern const char* GAUSSIAN_VERTICAL; +extern const char* GAUSSIAN_HORIZONTAL; #endif /* _TVG_GL_SHADERSRC_H_ */