This commit is contained in:
RuiwenTang 2025-05-15 21:40:41 +08:00 committed by GitHub
commit f9ea58b540
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 256 additions and 150 deletions

View file

@ -165,7 +165,7 @@ struct GlRadialGradientBlock
struct GlCompositor : RenderCompositor
{
RenderRegion bbox = {};
BlendMethod blend = BlendMethod::Normal;
GlCompositor(const RenderRegion& box) : bbox(box) {}
};

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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);

View file

@ -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<uint32_t>(vp.w), static_cast<uint32_t>(vp.h));
@ -77,6 +77,7 @@ public:
GlRenderTarget* getFbo() { return mFbo; }
private:
GlRenderTarget* mFbo;
RenderRegion mViewport;
Array<GlRenderTask*> mTasks = {};
int32_t mDrawDepth = 0;
};

View file

@ -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;
}

View file

@ -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 {

View file

@ -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);
}

View file

@ -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

View file

@ -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<int32_t>((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<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)
{
@ -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<GlDrawBlitTask>(mPrograms[RT_Image], currentPass()->getFboId());
task->setRenderSize(static_cast<uint32_t>(glCmp->bbox.w), static_cast<uint32_t>(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<uint32_t>(currentPass()->getViewport().w), static_cast<uint32_t>(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<int32_t>(surface.w), static_cast<int32_t>(surface.h)}));
return true;
}
@ -940,13 +968,14 @@ bool GlRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_
}
auto glCmp = static_cast<GlCompositor*>(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;
}
}

View file

@ -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);

View file

@ -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);
}
)";

View file

@ -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_ */