diff --git a/src/renderer/gl_engine/tvgGlCommon.h b/src/renderer/gl_engine/tvgGlCommon.h index 1dc2492d..d95ebf67 100644 --- a/src/renderer/gl_engine/tvgGlCommon.h +++ b/src/renderer/gl_engine/tvgGlCommon.h @@ -165,7 +165,7 @@ struct GlRadialGradientBlock struct GlCompositor : RenderCompositor { RenderRegion bbox = {}; - + BlendMethod blend = BlendMethod::Normal; GlCompositor(const RenderRegion& box) : bbox(box) {} }; diff --git a/src/renderer/gl_engine/tvgGlProgram.cpp b/src/renderer/gl_engine/tvgGlProgram.cpp index e3ac313d..a16ce38b 100644 --- a/src/renderer/gl_engine/tvgGlProgram.cpp +++ b/src/renderer/gl_engine/tvgGlProgram.cpp @@ -101,13 +101,17 @@ int32_t GlProgram::getAttributeLocation(const char* name) int32_t GlProgram::getUniformLocation(const char* name) { + if (mUniformLocation.count(name)) return mUniformLocation[name]; GL_CHECK(int32_t location = glGetUniformLocation(mProgramObj, name)); + mUniformLocation[name] = location; return location; } int32_t GlProgram::getUniformBlockIndex(const char* name) { + if (mUniformBlock.count(name)) return mUniformBlock[name]; GL_CHECK(int32_t index = glGetUniformBlockIndex(mProgramObj, name)); + mUniformBlock[name] = index; return index; } diff --git a/src/renderer/gl_engine/tvgGlProgram.h b/src/renderer/gl_engine/tvgGlProgram.h index d6d65e29..fabf08b0 100644 --- a/src/renderer/gl_engine/tvgGlProgram.h +++ b/src/renderer/gl_engine/tvgGlProgram.h @@ -25,6 +25,9 @@ #include "tvgGlShader.h" +#include +#include + class GlProgram { public: @@ -49,6 +52,8 @@ public: private: uint32_t mProgramObj; + std::unordered_map mUniformLocation; + std::unordered_map mUniformBlock; static uint32_t mCurrentProgram; }; diff --git a/src/renderer/gl_engine/tvgGlRenderPass.cpp b/src/renderer/gl_engine/tvgGlRenderPass.cpp index 743b5abd..74764674 100644 --- a/src/renderer/gl_engine/tvgGlRenderPass.cpp +++ b/src/renderer/gl_engine/tvgGlRenderPass.cpp @@ -25,9 +25,9 @@ #include "tvgGlRenderPass.h" #include "tvgGlRenderTask.h" -GlRenderPass::GlRenderPass(GlRenderTarget* fbo): mFbo(fbo), mTasks(), mDrawDepth(0) {} +GlRenderPass::GlRenderPass(GlRenderTarget* fbo, RenderRegion viewport): mFbo(fbo), mViewport(viewport), mTasks(), mDrawDepth(0) {} -GlRenderPass::GlRenderPass(GlRenderPass&& other): mFbo(other.mFbo), mTasks(), mDrawDepth(0) +GlRenderPass::GlRenderPass(GlRenderPass&& other): mFbo(other.mFbo), mViewport(other.mViewport), mTasks(), mDrawDepth(0) { mTasks.push(other.mTasks); diff --git a/src/renderer/gl_engine/tvgGlRenderPass.h b/src/renderer/gl_engine/tvgGlRenderPass.h index 96890f06..da254bd7 100644 --- a/src/renderer/gl_engine/tvgGlRenderPass.h +++ b/src/renderer/gl_engine/tvgGlRenderPass.h @@ -32,7 +32,7 @@ class GlProgram; class GlRenderPass { public: - GlRenderPass(GlRenderTarget* fbo); + GlRenderPass(GlRenderTarget* fbo, RenderRegion viewport); GlRenderPass(GlRenderPass&& other); ~GlRenderPass(); @@ -45,7 +45,7 @@ public: GLuint getTextureId() { return mFbo->getColorTexture(); } - const RenderRegion& getViewport() const { return mFbo->getViewport(); } + const RenderRegion& getViewport() const { return mViewport; } uint32_t getFboWidth() const { return mFbo->getWidth(); } @@ -63,7 +63,7 @@ public: auto task = new T(program, targetFbo, mFbo, std::move(mTasks)); - const auto& vp = mFbo->getViewport(); + const auto& vp = mViewport; task->setRenderSize(static_cast(vp.w), static_cast(vp.h)); @@ -77,6 +77,7 @@ public: GlRenderTarget* getFbo() { return mFbo; } private: GlRenderTarget* mFbo; + RenderRegion mViewport; Array mTasks = {}; int32_t mDrawDepth = 0; }; diff --git a/src/renderer/gl_engine/tvgGlRenderTarget.cpp b/src/renderer/gl_engine/tvgGlRenderTarget.cpp index 47c2f831..4837d41d 100644 --- a/src/renderer/gl_engine/tvgGlRenderTarget.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTarget.cpp @@ -29,6 +29,7 @@ GlRenderTarget::~GlRenderTarget() if (mFbo == 0) return; GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0)); GL_CHECK(glDeleteFramebuffers(1, &mFbo)); + GL_CHECK(glDeleteFramebuffers(1, &mResolveFbo)); if (mColorTex != 0) { GL_CHECK(glDeleteTextures(1, &mColorTex)); @@ -36,6 +37,9 @@ GlRenderTarget::~GlRenderTarget() if (mDepthStencilBuffer != 0) { GL_CHECK(glDeleteRenderbuffers(1, &mDepthStencilBuffer)); } + if (mColorBuffer!= 0) { + GL_CHECK(glDeleteRenderbuffers(1, &mColorBuffer)); + } } void GlRenderTarget::init(GLint resolveId) @@ -119,15 +123,15 @@ GlRenderTarget* GlRenderTargetPool::getRenderTarget(const RenderRegion& vp, GLui 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() == width && rt->getHeight() == height && !rt->isInUse()) { + rt->setInUse(true); return rt; } } auto rt = new GlRenderTarget(width, height); rt->init(resolveId); - rt->setViewport(vp); + rt->setInUse(true); mPool.push(rt); return rt; } diff --git a/src/renderer/gl_engine/tvgGlRenderTarget.h b/src/renderer/gl_engine/tvgGlRenderTarget.h index 2cc9733b..f85f9e4e 100644 --- a/src/renderer/gl_engine/tvgGlRenderTarget.h +++ b/src/renderer/gl_engine/tvgGlRenderTarget.h @@ -45,16 +45,19 @@ public: const RenderRegion& getViewport() const { return mViewport; } bool invalid() const { return mFbo == GL_INVALID_VALUE; } + bool isInUse() const { return mInUse; } + void setInUse(bool inUse) { mInUse = inUse; } private: - uint32_t mWidth = 0; - uint32_t mHeight = 0; + uint32_t mWidth; + uint32_t mHeight; RenderRegion mViewport{}; GLuint mFbo = GL_INVALID_VALUE; GLuint mColorBuffer = 0; GLuint mDepthStencilBuffer = 0; GLuint mResolveFbo = 0; GLuint mColorTex = 0; + bool mInUse = false; }; class GlRenderTargetPool { diff --git a/src/renderer/gl_engine/tvgGlRenderTask.cpp b/src/renderer/gl_engine/tvgGlRenderTask.cpp index 0464b35f..f354e59e 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTask.cpp @@ -332,12 +332,11 @@ void GlSimpleBlendTask::run() glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } -GlComplexBlendTask::GlComplexBlendTask(GlProgram* program, GlRenderTarget* dstFbo, GlRenderTarget* dstCopyFbo, GlRenderTask* stencilTask, GlComposeTask* composeTask) - : GlRenderTask(program), mDstFbo(dstFbo), mDstCopyFbo(dstCopyFbo), mStencilTask(stencilTask), mComposeTask(composeTask) {} +GlComplexBlendTask::GlComplexBlendTask(GlProgram* program, GlRenderTarget* dstFbo, GlRenderTarget* dstCopyFbo, GlComposeTask* composeTask) + : GlRenderTask(program), mDstFbo(dstFbo), mDstCopyFbo(dstCopyFbo), mComposeTask(composeTask) {} GlComplexBlendTask::~GlComplexBlendTask() { - delete mStencilTask; delete mComposeTask; } @@ -349,8 +348,8 @@ void GlComplexBlendTask::run() GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, mDstFbo->getFboId())); GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDstCopyFbo->getResolveFboId())); - GL_CHECK(glViewport(0, 0, mDstFbo->getViewport().w, mDstFbo->getViewport().h)); - GL_CHECK(glScissor(0, 0, mDstFbo->getViewport().w, mDstFbo->getViewport().h)); + GL_CHECK(glViewport(0, 0, mViewport.w, mViewport.h)); + GL_CHECK(glScissor(0, 0, mViewport.w, mViewport.h)); const auto& vp = getViewport(); @@ -358,21 +357,6 @@ void GlComplexBlendTask::run() GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstFbo->getFboId())); - GL_CHECK(glEnable(GL_STENCIL_TEST)); - GL_CHECK(glColorMask(0, 0, 0, 0)); - GL_CHECK(glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0x0, 0xFF)); - GL_CHECK(glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP)); - - GL_CHECK(glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0x0, 0xFF)); - GL_CHECK(glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP)); - - - mStencilTask->run(); - - GL_CHECK(glColorMask(1, 1, 1, 1)); - GL_CHECK(glStencilFunc(GL_NOTEQUAL, 0x0, 0xFF)); - GL_CHECK(glStencilOp(GL_REPLACE, GL_KEEP, GL_REPLACE)); - GL_CHECK(glBlendFunc(GL_ONE, GL_ZERO)); GlRenderTask::run(); @@ -383,7 +367,6 @@ void GlComplexBlendTask::run() void GlComplexBlendTask::normalizeDrawDepth(int32_t maxDepth) { - mStencilTask->normalizeDrawDepth(maxDepth); GlRenderTask::normalizeDrawDepth(maxDepth); } diff --git a/src/renderer/gl_engine/tvgGlRenderTask.h b/src/renderer/gl_engine/tvgGlRenderTask.h index d6fa93f2..4622e795 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.h +++ b/src/renderer/gl_engine/tvgGlRenderTask.h @@ -206,17 +206,21 @@ private: class GlComplexBlendTask: public GlRenderTask { public: - GlComplexBlendTask(GlProgram* program, GlRenderTarget* dstFbo, GlRenderTarget* dstCopyFbo, GlRenderTask* stencilTask, GlComposeTask* composeTask); + GlComplexBlendTask(GlProgram* program, GlRenderTarget* dstFbo, GlRenderTarget* dstCopyFbo, GlComposeTask* composeTask); ~GlComplexBlendTask() override; void run() override; void normalizeDrawDepth(int32_t maxDepth) override; + + void setViewport(const RenderRegion& viewport) { mViewport = viewport; } + void setCopyViewport(const RenderRegion& viewport) { mCopyViewport = viewport; } private: GlRenderTarget* mDstFbo; GlRenderTarget* mDstCopyFbo; - GlRenderTask* mStencilTask; GlComposeTask* mComposeTask; + RenderRegion mViewport = {}; + RenderRegion mCopyViewport = {}; }; class GlGaussianBlurTask: public GlRenderTask diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index e177854e..afab0e3e 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -156,6 +156,8 @@ 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)); + mPrograms.push(new GlProgram(MASK_VERT_SHADER, LIGHTEN_BLEND_FRAG)); + mPrograms.push(new GlProgram(MASK_VERT_SHADER, DARKEN_BLEND_FRAG)); // effects mPrograms.push(new GlProgram(EFFECT_VERTEX, GAUSSIAN_VERTICAL)); @@ -174,7 +176,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const RenderColor& c, RenderUpdat bbox.intersect(vp); - auto complexBlend = beginComplexBlending(bbox, sdata.geometry.getBounds()); + auto complexBlend = beginComplexBlending(mBlendMethod, bbox, sdata.geometry.getBounds()); if (complexBlend) { vp = currentPass()->getViewport(); @@ -254,11 +256,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const RenderColor& c, RenderUpdat if (stencilTask) currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task, stencilMode)); else currentPass()->addRenderTask(task); - if (complexBlend) { - auto task = new GlRenderTask(mPrograms[RT_Stencil]); - sdata.geometry.draw(task, &mGpuBuffer, flag); - endBlendingCompose(task, sdata.geometry.matrix); - } + if (complexBlend) endBlendingCompose(mBlendMethod); } @@ -290,7 +288,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla return; } - auto complexBlend = beginComplexBlending(bbox, sdata.geometry.getBounds()); + auto complexBlend = beginComplexBlending(mBlendMethod, bbox, sdata.geometry.getBounds()); if (complexBlend) vp = currentPass()->getViewport(); @@ -441,11 +439,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla currentPass()->addRenderTask(task); } - if (complexBlend) { - auto task = new GlRenderTask(mPrograms[RT_Stencil]); - sdata.geometry.draw(task, &mGpuBuffer, flag); - endBlendingCompose(task, sdata.geometry.matrix); - } + if (complexBlend) endBlendingCompose(mBlendMethod); } @@ -539,7 +533,7 @@ GlRenderPass* GlRenderer::currentPass() return mRenderPassStack.last(); } -bool GlRenderer::beginComplexBlending(const RenderRegion& vp, RenderRegion bounds) +bool GlRenderer::beginComplexBlending(BlendMethod blend, const RenderRegion& vp, RenderRegion bounds) { if (vp.w == 0 || vp.h == 0) return false; @@ -547,18 +541,18 @@ bool GlRenderer::beginComplexBlending(const RenderRegion& vp, RenderRegion bound if (bounds.w == 0 || bounds.h == 0) return false; - if (mBlendMethod == BlendMethod::Normal || mBlendMethod == BlendMethod::Add || mBlendMethod == BlendMethod::Darken || mBlendMethod == BlendMethod::Lighten) return false; + if (blend == BlendMethod::Normal || blend == BlendMethod::Add) return false; if (mBlendPool.empty()) mBlendPool.push(new GlRenderTargetPool(surface.w, surface.h)); auto blendFbo = mBlendPool[0]->getRenderTarget(bounds); - mRenderPassStack.push(new GlRenderPass(blendFbo)); + mRenderPassStack.push(new GlRenderPass(blendFbo, bounds)); return true; } -void GlRenderer::endBlendingCompose(GlRenderTask* stencilTask, const Matrix& matrix) +void GlRenderer::endBlendingCompose(BlendMethod blend) { auto blendPass = mRenderPassStack.last(); mRenderPassStack.pop(); @@ -571,34 +565,10 @@ void GlRenderer::endBlendingCompose(GlRenderTask* stencilTask, const Matrix& mat if (mBlendPool.count < 2) mBlendPool.push(new GlRenderTargetPool(surface.w, surface.h)); auto dstCopyFbo = mBlendPool[1]->getRenderTarget(vp); - { - const auto& passVp = currentPass()->getViewport(); + auto task = new GlComplexBlendTask(getBlendProgram(blend), currentPass()->getFbo(), dstCopyFbo, composeTask); - 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}); - } - - stencilTask->setDrawDepth(currentPass()->nextDrawDepth()); - - { - // set view matrix - float matrix44[16]; - currentPass()->getMatrix(matrix44, matrix); - uint32_t viewOffset = mGpuBuffer.push(matrix44, 16 * sizeof(float), true); - stencilTask->addBindResource(GlBindingResource{ - 0, - stencilTask->getProgram()->getUniformBlockIndex("Matrix"), - mGpuBuffer.getBufferId(), - viewOffset, - 16 * sizeof(float), - }); - } - - auto task = new GlComplexBlendTask(getBlendProgram(), currentPass()->getFbo(), dstCopyFbo, stencilTask, composeTask); + task->setViewport(currentPass()->getViewport()); + task->setCopyViewport(blendPass->getViewport()); prepareCmpTask(task, vp, blendPass->getFboWidth(), blendPass->getFboHeight()); @@ -613,9 +583,9 @@ void GlRenderer::endBlendingCompose(GlRenderTask* stencilTask, const Matrix& mat delete(blendPass); } -GlProgram* GlRenderer::getBlendProgram() +GlProgram* GlRenderer::getBlendProgram(BlendMethod blend) { - switch (mBlendMethod) { + switch (blend) { case BlendMethod::Multiply: return mPrograms[RT_MultiplyBlend]; case BlendMethod::Screen: return mPrograms[RT_ScreenBlend]; case BlendMethod::Overlay: return mPrograms[RT_OverlayBlend]; @@ -625,6 +595,8 @@ GlProgram* GlRenderer::getBlendProgram() case BlendMethod::SoftLight: return mPrograms[RT_SoftLightBlend]; case BlendMethod::Difference: return mPrograms[RT_DifferenceBlend]; case BlendMethod::Exclusion: return mPrograms[RT_ExclusionBlend]; + case BlendMethod::Lighten: return mPrograms[RT_LightenBlend]; + case BlendMethod::Darken: return mPrograms[RT_DarkenBlend]; default: return nullptr; } } @@ -711,6 +683,41 @@ void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint task->setViewport({x, static_cast((passVp.h - y - h)), w, h}); } +void GlRenderer::prepareCmpStencilTask(GlRenderTask* task, RenderRegion& vp) +{ + auto x = 0; + auto y = 0; + auto w = vp.w; + auto h = vp.h; + + Array vertices(4 * 2); + // left top + vertices.push(x); + vertices.push(y); + // left bottom + vertices.push(x); + vertices.push(y + h); + // right top + vertices.push(x + w); + vertices.push(y); + // right bottom + vertices.push(x + w); + vertices.push(y + h); + + 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)); + task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), vertexOffset}); + task->setDrawRange(indexOffset, indices.count); +} + void GlRenderer::endRenderPass(RenderCompositor* cmp) { @@ -723,6 +730,8 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp) auto maskPass = mRenderPassStack.last(); mRenderPassStack.pop(); + bool complexBlend = beginComplexBlending(glCmp->blend, glCmp->bbox, glCmp->bbox); + GlProgram* program = nullptr; switch(cmp->method) { case MaskMethod::Alpha: program = mPrograms[RT_MaskAlpha]; break; @@ -758,6 +767,11 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp) currentPass()->addRenderTask(compose_task); } + if (complexBlend) endBlendingCompose(glCmp->blend); + + maskPass->getFbo()->setInUse(false); + selfPass->getFbo()->setInUse(false); + delete(selfPass); delete(maskPass); } else { @@ -766,6 +780,8 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp) mRenderPassStack.pop(); if (!renderPass->isEmpty()) { + bool complexBlend = beginComplexBlending(glCmp->blend, glCmp->bbox, glCmp->bbox); + 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()); @@ -793,10 +809,22 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp) 4 * sizeof(uint32_t), }); + task->addBindResource(GlBindingResource{ + 1, + task->getProgram()->getUniformBlockIndex("ColorInfo"), + mGpuBuffer.getBufferId(), + mGpuBuffer.push(info, 4 * sizeof(uint32_t), true), + 4 * sizeof(uint32_t), + }); + // texture id task->addBindResource(GlBindingResource{0, renderPass->getTextureId(), task->getProgram()->getUniformLocation("uTexture")}); task->setParentSize(static_cast(currentPass()->getViewport().w), static_cast(currentPass()->getViewport().h)); currentPass()->addRenderTask(std::move(task)); + + if (complexBlend) endBlendingCompose(glCmp->blend); + renderPass->getFbo()->setInUse(false); + } delete(renderPass); } @@ -902,7 +930,7 @@ bool GlRenderer::preRender() currentContext(); if (mPrograms.empty()) initShaders(); - mRenderPassStack.push(new GlRenderPass(&mRootTarget)); + mRenderPassStack.push(new GlRenderPass(&mRootTarget, RenderRegion{0, 0, static_cast(surface.w), static_cast(surface.h)})); return true; } @@ -940,13 +968,14 @@ bool GlRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_ } auto glCmp = static_cast(cmp); + glCmp->blend = mBlendMethod; if (glCmp->bbox.w > 0 && glCmp->bbox.h > 0) { auto renderTarget = mComposePool[index]->getRenderTarget(glCmp->bbox); - mRenderPassStack.push(new GlRenderPass(renderTarget)); + mRenderPassStack.push(new GlRenderPass(renderTarget, glCmp->bbox)); } else { // empty render pass - mRenderPassStack.push(new GlRenderPass(nullptr)); + mRenderPassStack.push(new GlRenderPass(nullptr, glCmp->bbox)); } return true; @@ -1265,6 +1294,10 @@ bool GlRenderer::renderImage(void* data) auto bbox = sdata->geometry.viewport; + bool complexBlend = beginComplexBlending(mBlendMethod, bbox, sdata->geometry.getBounds()); + + if (complexBlend) vp = currentPass()->getViewport(); + bbox.intersect(vp); if (bbox.w <= 0 || bbox.h <= 0) return true; @@ -1277,7 +1310,10 @@ bool GlRenderer::renderImage(void* data) if (!sdata->clips.empty()) drawClip(sdata->clips); - auto task = new GlRenderTask(mPrograms[RT_Image]); + GlRenderTask* task = nullptr; + if (mBlendMethod != BlendMethod::Normal && !complexBlend) task = new GlSimpleBlendTask(mBlendMethod, mPrograms[RT_Image]); + else task = new GlRenderTask(mPrograms[RT_Image]); + task->setDrawDepth(drawDepth); if (!sdata->geometry.draw(task, &mGpuBuffer, RenderUpdateFlag::Image)) { @@ -1285,10 +1321,6 @@ bool GlRenderer::renderImage(void* data) return true; } - bool complexBlend = beginComplexBlending(bbox, sdata->geometry.getBounds()); - - if (complexBlend) vp = currentPass()->getViewport(); - // matrix buffer float matrix44[16]; currentPass()->getMatrix(matrix44, sdata->geometry.matrix); @@ -1319,11 +1351,7 @@ bool GlRenderer::renderImage(void* data) currentPass()->addRenderTask(task); - if (complexBlend) { - auto task = new GlRenderTask(mPrograms[RT_Stencil]); - sdata->geometry.draw(task, &mGpuBuffer, RenderUpdateFlag::Image); - endBlendingCompose(task, sdata->geometry.matrix); - } + if (complexBlend) endBlendingCompose(mBlendMethod); return true; } @@ -1566,4 +1594,4 @@ GlRenderer* GlRenderer::gen(TVG_UNUSED uint32_t threads) } return new GlRenderer; -} \ No newline at end of file +} diff --git a/src/renderer/gl_engine/tvgGlRenderer.h b/src/renderer/gl_engine/tvgGlRenderer.h index 7ab1e901..fb48d1b0 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.h +++ b/src/renderer/gl_engine/tvgGlRenderer.h @@ -59,6 +59,8 @@ public: RT_SoftLightBlend, RT_DifferenceBlend, RT_ExclusionBlend, + RT_LightenBlend, + RT_DarkenBlend, RT_GaussianVert, RT_GaussianHorz, @@ -113,12 +115,13 @@ private: GlRenderPass* currentPass(); - bool beginComplexBlending(const RenderRegion& vp, RenderRegion bounds); - void endBlendingCompose(GlRenderTask* stencilTask, const Matrix& matrix); - GlProgram* getBlendProgram(); + bool beginComplexBlending(BlendMethod blend, const RenderRegion& vp, RenderRegion bounds); + void endBlendingCompose(BlendMethod blend); + GlProgram* getBlendProgram(BlendMethod blend); void prepareBlitTask(GlBlitTask* task); void prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint32_t cmpWidth, uint32_t cmpHeight); + void prepareCmpStencilTask(GlRenderTask* task, RenderRegion& vp); void endRenderPass(RenderCompositor* cmp); void effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform); diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.cpp b/src/renderer/gl_engine/tvgGlShaderSrc.cpp index 73d5e8ae..43b401ae 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.cpp +++ b/src/renderer/gl_engine/tvgGlShaderSrc.cpp @@ -598,131 +598,199 @@ const char* BLIT_FRAG_SHADER = TVG_COMPOSE_SHADER( \ in vec2 vUV; \ out vec4 FragColor; \ + + // 1/1024. + const float kEhCloseEnoughHalf = 0.0009765625; )" const char* MULTIPLY_BLEND_FRAG = COMPLEX_BLEND_HEADER R"( void main() { - vec4 srcColor = texture(uSrcTexture, vUV); - vec4 dstColor = texture(uDstTexture, vUV); - FragColor = srcColor * dstColor; + vec4 src = texture(uSrcTexture, vUV); + vec4 dst = texture(uDstTexture, vUV); + + FragColor = vec4((1.0 - src.a)*dst.rgb + (1.0 - dst.a)*src.rgb + src.rgb*dst.rgb, src.a + (1.0 - src.a)*dst.a); } )"; -#define SCREEN_BLEND_FUNC R"( \ - vec4 screenBlend(vec4 srcColor, vec4 dstColor) \ - { \ - return dstColor + srcColor - (dstColor * srcColor); \ - } \ -)" - -#define HARD_LIGHT_BLEND_FUNC R"( \ - vec4 hardLightBlend(vec4 srcColor, vec4 dstColor) \ - { \ - return vec4(srcColor.r < 0.5 ? 2.0 * srcColor.r * dstColor.r : 1.0 - 2.0 * (1.0 - srcColor.r) * (1.0 - dstColor.r), \ - srcColor.g < 0.5 ? 2.0 * srcColor.g * dstColor.g : 1.0 - 2.0 * (1.0 - srcColor.g) * (1.0 - dstColor.g), \ - srcColor.b < 0.5 ? 2.0 * srcColor.b * dstColor.b : 1.0 - 2.0 * (1.0 - srcColor.b) * (1.0 - dstColor.b), \ - 1.0); \ - } \ -)" - -#define SOFT_LIGHT_BLEND_FUNC R"( \ - float softLightD(float v) \ - { \ - if (v <= 0.25) return ((16.0 * v - 12.0) * v + 4.0) * v; \ - else return sqrt(v); \ - } \ -)" - -const char* SCREEN_BLEND_FRAG = COMPLEX_BLEND_HEADER SCREEN_BLEND_FUNC R"( +const char* SCREEN_BLEND_FRAG = COMPLEX_BLEND_HEADER R"( void main() { vec4 srcColor = texture(uSrcTexture, vUV); vec4 dstColor = texture(uDstTexture, vUV); - FragColor = screenBlend(srcColor, dstColor); + FragColor = srcColor + (1.0 - srcColor) * dstColor; } )"; -const char* OVERLAY_BLEND_FRAG = COMPLEX_BLEND_HEADER HARD_LIGHT_BLEND_FUNC R"( +#define BLEND_OVERLAY_FUNC R"( + float blend_overlay_component(vec2 s, vec2 d) + { + return (2.0 * d.x <= d.y) ? 2.0 * s.x * d.x + : s.y * d.y - 2.0 * (d.y - d.x) * (s.y - s.x); + } + + vec4 blend_overlay(vec4 src, vec4 dst) + { + vec4 result = vec4( + blend_overlay_component(src.ra, dst.ra), + blend_overlay_component(src.ga, dst.ga), + blend_overlay_component(src.ba, dst.ba), + src.a + (1.0 - src.a) * dst.a + ); + + result.rgb += dst.rgb*(1 - src.a) + src.rgb*(1 - dst.a); + + return result; + } +)" + +const char* OVERLAY_BLEND_FRAG = COMPLEX_BLEND_HEADER BLEND_OVERLAY_FUNC R"( void main() { vec4 srcColor = texture(uSrcTexture, vUV); vec4 dstColor = texture(uDstTexture, vUV); - FragColor = hardLightBlend(dstColor, srcColor); + + FragColor = blend_overlay(srcColor, dstColor); } )"; const char* COLOR_DODGE_BLEND_FRAG = COMPLEX_BLEND_HEADER R"( + float color_dodge_component(vec2 s, vec2 d) + { + float dxScale = d.x == 0.0 ? 0.0 : 1.0; + float delta = dxScale * min(d.y, abs(s.y - s.x) >= kEhCloseEnoughHalf ? (d.x * s.y / (s.y - s.x)) : d.y); + + return delta * s.y + s.x * (1.0 - d.y) + d.x * (1.0 - s.y); + } + void main() { vec4 srcColor = texture(uSrcTexture, vUV); vec4 dstColor = texture(uDstTexture, vUV); FragColor = vec4( - srcColor.r < 1.0 ? dstColor.r / (1.0 - srcColor.r) : (dstColor.r > 0.0 ? 1.0 : 0.0), - srcColor.g < 1.0 ? dstColor.g / (1.0 - srcColor.g) : (dstColor.g > 0.0 ? 1.0 : 0.0), - srcColor.b < 1.0 ? dstColor.b / (1.0 - srcColor.b) : (dstColor.b > 0.0 ? 1.0 : 0.0), - 1.0 + color_dodge_component(srcColor.ra, dstColor.ra), + color_dodge_component(srcColor.ga, dstColor.ga), + color_dodge_component(srcColor.ba, dstColor.ba), + srcColor.a + (1.0 - srcColor.a) * dstColor.a ); } )"; const char* COLOR_BURN_BLEND_FRAG = COMPLEX_BLEND_HEADER R"( + float color_burn_component(vec2 s, vec2 d) + { + float dyTerm = d.y == d.x ? d.y : 0.0; + float delta = abs(s.x) >= kEhCloseEnoughHalf ? d.y - min(d.y, ((d.y - d.x) * s.y / s.x)) : dyTerm; + + return delta * s.y + s.x * (1.0 - d.y) + d.x * (1.0 - s.y); + } + void main() { vec4 srcColor = texture(uSrcTexture, vUV); vec4 dstColor = texture(uDstTexture, vUV); FragColor = vec4( - srcColor.r > 0.0 ? (1.0 - (1.0 - dstColor.r) / srcColor.r) : (dstColor.r < 1.0 ? 0.0 : 1.0), - srcColor.g > 0.0 ? (1.0 - (1.0 - dstColor.g) / srcColor.g) : (dstColor.g < 1.0 ? 0.0 : 1.0), - srcColor.b > 0.0 ? (1.0 - (1.0 - dstColor.b) / srcColor.b) : (dstColor.b < 1.0 ? 0.0 : 1.0), - 1.0 + color_burn_component(srcColor.ra, dstColor.ra), + color_burn_component(srcColor.ga, dstColor.ga), + color_burn_component(srcColor.ba, dstColor.ba), + srcColor.a + (1.0 - srcColor.a) * dstColor.a ); } )"; -const char* HARD_LIGHT_BLEND_FRAG = COMPLEX_BLEND_HEADER HARD_LIGHT_BLEND_FUNC R"( +const char* HARD_LIGHT_BLEND_FRAG = COMPLEX_BLEND_HEADER BLEND_OVERLAY_FUNC R"( void main() { vec4 srcColor = texture(uSrcTexture, vUV); vec4 dstColor = texture(uDstTexture, vUV); - FragColor = hardLightBlend(srcColor, dstColor); + + FragColor = blend_overlay(dstColor, srcColor); } )"; -const char* SOFT_LIGHT_BLEND_FRAG = COMPLEX_BLEND_HEADER SOFT_LIGHT_BLEND_FUNC R"( +const char* SOFT_LIGHT_BLEND_FRAG = COMPLEX_BLEND_HEADER R"( + float soft_light_component(vec2 s, vec2 d) + { + if (2.0 * s.x <= s.y) { + return (d.x * d.x * (s.y - 2.0 * s.x) / d.y) + (1.0 - d.y) * s.x + d.x * (-s.y + 2.0 * s.x + 1.0); + } else if(4.0 * d.x <= d.y) { + float DSqd = d.x * d.x; + float DCub = DSqd * d.x; + float DaSqd = d.y * d.y; + float DaCub = DaSqd * d.y; + + return (DaSqd * (s.x - d.x * (3.0 * s.y - 6.0 * s.x - 1.0)) + 12.0 * d.y * DSqd * (s.y - 2.0 * s.x) - 16.0 * DCub * (s.y - 2.0 * s.x) - DaCub * s.x) / DaSqd; + } else { + return d.x * (s.y - 2.0 * s.x + 1.0) + s.x - sqrt(d.y * d.x) * (s.y - 2.0 * s.x) - d.y * s.x; + } + } + void main() { vec4 srcColor = texture(uSrcTexture, vUV); vec4 dstColor = texture(uDstTexture, vUV); - FragColor = vec4( - srcColor.r <= 0.5 ? dstColor.r - (1.0 - 2.0 * srcColor.r) * dstColor.r * (1.0 - dstColor.r) : dstColor.r + (2.0 * srcColor.r - 1.0) * (softLightD(dstColor.r) - dstColor.r), - srcColor.g <= 0.5 ? dstColor.g - (1.0 - 2.0 * srcColor.g) * dstColor.g * (1.0 - dstColor.g) : dstColor.g + (2.0 * srcColor.g - 1.0) * (softLightD(dstColor.g) - dstColor.g), - srcColor.b <= 0.5 ? dstColor.b - (1.0 - 2.0 * srcColor.b) * dstColor.b * (1.0 - dstColor.b) : dstColor.b + (2.0 * srcColor.b - 1.0) * (softLightD(dstColor.b) - dstColor.b), - 1.0 - ); + FragColor = dstColor.a == 0.0 ? srcColor : vec4( + soft_light_component(srcColor.ra, dstColor.ra), + soft_light_component(srcColor.ga, dstColor.ga), + soft_light_component(srcColor.ba, dstColor.ba), + srcColor.a + (1.0 - srcColor.a) * dstColor.a + ); } )"; const char* DIFFERENCE_BLEND_FRAG = COMPLEX_BLEND_HEADER R"( void main() { - vec4 srcColor = texture(uSrcTexture, vUV); - vec4 dstColor = texture(uDstTexture, vUV); + vec4 src = texture(uSrcTexture, vUV); + vec4 dst = texture(uDstTexture, vUV); - FragColor = abs(dstColor - srcColor); + FragColor = vec4(src.rgb + dst.rgb - 2.0 * min(src.rgb * dst.a, dst.rgb * src.a), src.a + (1.0 - src.a) * dst.a); } )"; const char* EXCLUSION_BLEND_FRAG = COMPLEX_BLEND_HEADER R"( + void main() + { + vec4 src = texture(uSrcTexture, vUV); + vec4 dst = texture(uDstTexture, vUV); + + FragColor = vec4(dst.rgb + src.rgb - 2.0 * dst.rgb * src.rgb, src.a + (1.0 - src.a) * dst.a); + } +)"; + +#define LD_BLEND_FUNC R"( + vec4 blendSrcOver(vec4 src, vec4 dst) { return src + (1 - src.a)*dst; } + + vec4 blendLightDarken(float mode, vec4 src, vec4 dst) + { + vec4 a = blendSrcOver(src, dst); + vec3 b = (1.0 - dst.a) * src.rgb + dst.rgb; + a.rgb = mode * min(a.rgb * mode, b.rgb * mode); + + return a; + } +)" + +const char* LIGHTEN_BLEND_FRAG = COMPLEX_BLEND_HEADER LD_BLEND_FUNC R"( void main() { vec4 srcColor = texture(uSrcTexture, vUV); vec4 dstColor = texture(uDstTexture, vUV); - FragColor = dstColor + srcColor - (2.0 * dstColor * srcColor); + FragColor = blendLightDarken(-1.0, srcColor, dstColor); + } +)"; + +const char* DARKEN_BLEND_FRAG = COMPLEX_BLEND_HEADER LD_BLEND_FUNC R"( + void main() + { + vec4 srcColor = texture(uSrcTexture, vUV); + vec4 dstColor = texture(uDstTexture, vUV); + + FragColor = blendLightDarken(1.0, srcColor, dstColor); } )"; diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.h b/src/renderer/gl_engine/tvgGlShaderSrc.h index bc793168..e75062ea 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.h +++ b/src/renderer/gl_engine/tvgGlShaderSrc.h @@ -58,12 +58,15 @@ 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_VERTEX; +extern const char* LIGHTEN_BLEND_FRAG; +extern const char* DARKEN_BLEND_FRAG; extern const char* GAUSSIAN_VERTICAL; extern const char* GAUSSIAN_HORIZONTAL; +extern const char* EFFECT_VERTEX; extern const char* EFFECT_DROPSHADOW; extern const char* EFFECT_FILL; extern const char* EFFECT_TINT; extern const char* EFFECT_TRITONE; + #endif /* _TVG_GL_SHADERSRC_H_ */