mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-23 14:48:24 +00:00
Merge bfe707170f
into a80b0aa188
This commit is contained in:
commit
08ed352b0d
13 changed files with 254 additions and 140 deletions
|
@ -157,7 +157,7 @@ struct GlRadialGradientBlock
|
|||
struct GlCompositor : RenderCompositor
|
||||
{
|
||||
RenderRegion bbox = {};
|
||||
|
||||
BlendMethod blend = BlendMethod::Normal;
|
||||
GlCompositor(const RenderRegion& box) : bbox(box) {}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
#include "tvgGlShader.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
class GlProgram
|
||||
{
|
||||
public:
|
||||
|
@ -49,6 +52,8 @@ public:
|
|||
|
||||
private:
|
||||
uint32_t mProgramObj;
|
||||
std::unordered_map<std::string, int32_t> mUniformLocation;
|
||||
std::unordered_map<std::string, int32_t> mUniformBlock;
|
||||
static uint32_t mCurrentProgram;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<GlRenderTask*> mTasks = {};
|
||||
int32_t mDrawDepth = 0;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<float> 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<uint32_t> 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<GlDrawBlitTask>(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<int32_t>(surface.w), static_cast<int32_t>(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<GlCompositor*>(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;
|
||||
}
|
||||
|
@ -1235,6 +1274,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;
|
||||
|
||||
|
@ -1244,7 +1287,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)) {
|
||||
|
@ -1252,9 +1298,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);
|
||||
|
@ -1289,11 +1332,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;
|
||||
}
|
||||
|
@ -1521,4 +1560,4 @@ GlRenderer* GlRenderer::gen(TVG_UNUSED uint32_t threads)
|
|||
}
|
||||
|
||||
return new GlRenderer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
)";
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
Loading…
Add table
Reference in a new issue