diff --git a/src/renderer/gl_engine/tvgGlCommon.h b/src/renderer/gl_engine/tvgGlCommon.h index 547d69ce..ec7fc1e8 100644 --- a/src/renderer/gl_engine/tvgGlCommon.h +++ b/src/renderer/gl_engine/tvgGlCommon.h @@ -157,7 +157,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 e20ffe10..9c8953de 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 b9c4f89e..e4e3b4c6 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(); } @@ -62,7 +62,7 @@ public: } auto task = new T(program, targetFbo, mFbo, std::move(mTasks)); - task->setRenderSize(mFbo->getViewport().w(), mFbo->getViewport().h()); + task->setRenderSize(mViewport.w(), mViewport.h()); return task; } @@ -74,6 +74,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 d4dbf5de..fad6da10 100644 --- a/src/renderer/gl_engine/tvgGlRenderTarget.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTarget.cpp @@ -121,8 +121,8 @@ 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->isInUse() && rt->getWidth() == width && rt->getHeight() == height) { + rt->setInUse(true); return rt; } } @@ -130,6 +130,7 @@ GlRenderTarget* GlRenderTargetPool::getRenderTarget(const RenderRegion& vp, GLui auto rt = new GlRenderTarget(); rt->init(width, height, 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 7577b35e..8ebd9d4b 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 9cd206e2..e8adfaa6 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTask.cpp @@ -393,15 +393,14 @@ void GlSimpleBlendTask::run() /************************************************************************/ -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; } @@ -414,29 +413,14 @@ 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(); GL_CHECK(glBlitFramebuffer(vp.min.x, vp.min.y, vp.max.x, vp.max.y, 0, 0, vp.w(), vp.h(), GL_COLOR_BUFFER_BIT, GL_LINEAR)); 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(); @@ -448,7 +432,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 6254292a..fe29f88f 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.h +++ b/src/renderer/gl_engine/tvgGlRenderTask.h @@ -204,17 +204,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 3111277b..e1db2433 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -159,6 +159,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)); @@ -177,7 +179,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(); @@ -258,11 +260,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); } @@ -289,7 +287,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(); auto x = bbox.sx() - vp.sx(); @@ -439,11 +437,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); } @@ -533,25 +527,25 @@ 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.invalid()) return false; bounds.intersect(vp); if (bounds.invalid()) 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(); @@ -564,25 +558,11 @@ 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); - auto x = vp.sx(); - auto y = currentPass()->getViewport().sh() - vp.sy() - vp.sh(); - stencilTask->setViewport({{x, y}, {x + vp.sw(), y + vp.sh()}}); + auto task = new GlComplexBlendTask(getBlendProgram(blend), currentPass()->getFbo(), dstCopyFbo, composeTask); - stencilTask->setDrawDepth(currentPass()->nextDrawDepth()); + task->setViewport(currentPass()->getViewport()); + task->setCopyViewport(blendPass->getViewport()); - // 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); prepareCmpTask(task, vp, blendPass->getFboWidth(), blendPass->getFboHeight()); task->setDrawDepth(currentPass()->nextDrawDepth()); @@ -595,9 +575,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]; @@ -607,6 +587,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; } } @@ -691,6 +673,41 @@ void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint task->setViewport({{x, y}, {x + w, y + 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) { @@ -703,6 +720,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; @@ -738,6 +757,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 { @@ -746,6 +770,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(glCmp->bbox.w(), glCmp->bbox.h()); prepareCmpTask(task, glCmp->bbox, renderPass->getFboWidth(), renderPass->getFboHeight()); @@ -773,10 +799,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(currentPass()->getViewport().w(), currentPass()->getViewport().h()); currentPass()->addRenderTask(std::move(task)); + + if (complexBlend) endBlendingCompose(glCmp->blend); + renderPass->getFbo()->setInUse(false); + } delete(renderPass); } @@ -885,7 +923,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; } @@ -920,8 +958,9 @@ bool GlRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_ if (index >= mComposePool.count) mComposePool.push( new GlRenderTargetPool(surface.w, surface.h)); auto glCmp = static_cast(cmp); - if (glCmp->bbox.valid()) mRenderPassStack.push(new GlRenderPass(mComposePool[index]->getRenderTarget(glCmp->bbox))); - else mRenderPassStack.push(new GlRenderPass(nullptr)); + glCmp->blend = mBlendMethod; + if (glCmp->bbox.valid()) mRenderPassStack.push(new GlRenderPass(mComposePool[index]->getRenderTarget(glCmp->bbox), glCmp->bbox)); + else mRenderPassStack.push(new GlRenderPass(nullptr, glCmp->bbox)); return true; } @@ -1232,6 +1271,10 @@ bool GlRenderer::renderImage(void* data) auto vp = currentPass()->getViewport(); auto bbox = sdata->geometry.viewport; + + bool complexBlend = beginComplexBlending(mBlendMethod, bbox, sdata->geometry.getBounds()); + if (complexBlend) vp = currentPass()->getViewport(); + bbox.intersect(vp); if (bbox.invalid()) return true; @@ -1241,7 +1284,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)) { @@ -1249,9 +1295,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); @@ -1286,11 +1329,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; } @@ -1518,4 +1557,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 237fe0a8..6d7c79ad 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, @@ -117,12 +119,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_ */