diff --git a/src/renderer/gl_engine/tvgGlRenderPass.h b/src/renderer/gl_engine/tvgGlRenderPass.h index eb5783ae..abc3847f 100644 --- a/src/renderer/gl_engine/tvgGlRenderPass.h +++ b/src/renderer/gl_engine/tvgGlRenderPass.h @@ -61,6 +61,8 @@ public: GLuint getFboId() { return mFbo->getFboId(); } + GLuint getTextureId() { return mFbo->getColorTexture(); } + template T* endRenderPass(GlProgram* program, GLuint targetFbo) { return new T(program, targetFbo, mFbo->getFboId(), std::move(mTasks)); diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index ed3aec5e..85d2f6bd 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -116,7 +116,7 @@ bool GlRenderer::sync() RenderRegion GlRenderer::region(TVG_UNUSED RenderData data) { - return {0, 0, 0, 0}; + return {0, 0, static_cast(surface.w), static_cast(surface.h)}; } @@ -150,18 +150,14 @@ bool GlRenderer::beginComposite(Compositor* cmp, CompositeMethod method, uint8_t { if (!cmp) return false; - // TODO handle other composite method with recursive begin composite - cmp->method = method; cmp->opacity = opacity; - if (cmp->method == CompositeMethod::None) { - if (mPoolIndex >= mComposePool.size()) { - mComposePool.emplace_back(make_unique(surface.w, surface.h)); - mComposePool.back()->init(mTargetFboId); - } - mRenderPassStack.emplace_back(GlRenderPass(mComposePool[mPoolIndex++].get())); + if (mPoolIndex >= mComposePool.size()) { + mComposePool.emplace_back(make_unique(surface.w, surface.h)); + mComposePool.back()->init(mTargetFboId); } + mRenderPassStack.emplace_back(GlRenderPass(mComposePool[mPoolIndex++].get())); return true; } @@ -469,6 +465,16 @@ void GlRenderer::initShaders() // image Renderer mPrograms.push_back(make_unique(GlShader::gen(IMAGE_VERT_SHADER, IMAGE_FRAG_SHADER))); + + // compose Renderer + mPrograms.push_back(make_unique(GlShader::gen(MASK_VERT_SHADER, MASK_ALPHA_FRAG_SHADER))); + mPrograms.push_back(make_unique(GlShader::gen(MASK_VERT_SHADER, MASK_INV_ALPHA_FRAG_SHADER))); + mPrograms.push_back(make_unique(GlShader::gen(MASK_VERT_SHADER, MASK_LUMA_FRAG_SHADER))); + mPrograms.push_back(make_unique(GlShader::gen(MASK_VERT_SHADER, MASK_INV_LUMA_FRAG_SHADER))); + mPrograms.push_back(make_unique(GlShader::gen(MASK_VERT_SHADER, MASK_ADD_FRAG_SHADER))); + mPrograms.push_back(make_unique(GlShader::gen(MASK_VERT_SHADER, MASK_SUB_FRAG_SHADER))); + mPrograms.push_back(make_unique(GlShader::gen(MASK_VERT_SHADER, MASK_INTERSECT_FRAG_SHADER))); + mPrograms.push_back(make_unique(GlShader::gen(MASK_VERT_SHADER, MASK_DIFF_FRAG_SHADER))); } @@ -612,7 +618,7 @@ GlRenderPass* GlRenderer::currentPass() return &mRenderPassStack.back(); } -void GlRenderer::prepareCmpTask(GlRenderTask* task) +void GlRenderer::prepareCmpTask(GlRenderTask* task, float opacity) { // we use 1:1 blit mapping since compositor fbo is same size as root fbo Array vertices; @@ -626,25 +632,25 @@ void GlRenderer::prepareCmpTask(GlRenderTask* task) // left top point vertices.push(left); vertices.push(top); - vertices.push(1.f); + vertices.push(opacity); vertices.push(0.f); vertices.push(1.f); // left bottom point vertices.push(left); vertices.push(bottom); - vertices.push(1.f); + vertices.push(opacity); vertices.push(0.f); vertices.push(0.f); // right top point vertices.push(right); vertices.push(top); - vertices.push(1.f); + vertices.push(opacity); vertices.push(1.f); vertices.push(1.f); // right bottom point vertices.push(right); vertices.push(bottom); - vertices.push(1.f); + vertices.push(opacity); vertices.push(1.f); vertices.push(0.f); @@ -676,54 +682,115 @@ void GlRenderer::prepareCmpTask(GlRenderTask* task) void GlRenderer::endRenderPass(Compositor* cmp) { if (cmp->method != CompositeMethod::None) { - //TODO support advance composite method with recursive compositor - return; + auto self_pass = std::move(mRenderPassStack.back()); + mRenderPassStack.pop_back(); + + // mask is pushed first + auto mask_pass = std::move(mRenderPassStack.back()); + mRenderPassStack.pop_back(); + + GlProgram* program = nullptr; + switch(cmp->method) { + case CompositeMethod::ClipPath: + case CompositeMethod::AlphaMask: + program = mPrograms[RT_MaskAlpha].get(); + break; + case CompositeMethod::InvAlphaMask: + program = mPrograms[RT_MaskAlphaInv].get(); + break; + case CompositeMethod::LumaMask: + program = mPrograms[RT_MaskLuma].get(); + break; + case CompositeMethod::InvLumaMask: + program = mPrograms[RT_MaskLumaInv].get(); + break; + case CompositeMethod::AddMask: + program = mPrograms[RT_MaskAdd].get(); + break; + case CompositeMethod::SubtractMask: + program = mPrograms[RT_MaskSub].get(); + break; + case CompositeMethod::IntersectMask: + program = mPrograms[RT_MaskIntersect].get(); + break; + case CompositeMethod::DifferenceMask: + program = mPrograms[RT_MaskDifference].get(); + break; + default: + break; + } + + if (program == nullptr) { + return; + } + + auto prev_task = mask_pass.endRenderPass(nullptr, currentPass()->getFboId()); + + currentPass()->addRenderTask(prev_task); + + auto compose_task = self_pass.endRenderPass(program, currentPass()->getFboId()); + + prepareCmpTask(compose_task, cmp->opacity / 255.f); + + { + uint32_t loc = program->getUniformLocation("uSrcTexture"); + compose_task->addBindResource(GlBindingResource{0, self_pass.getTextureId(), loc}); + } + + { + uint32_t loc = program->getUniformLocation("uMaskTexture"); + compose_task->addBindResource(GlBindingResource{1, mask_pass.getTextureId(), loc}); + } + + + currentPass()->addRenderTask(compose_task); + } else { + + auto renderPass = std::move(mRenderPassStack.back()); + mRenderPassStack.pop_back(); + + auto task = renderPass.endRenderPass( + mPrograms[RT_Image].get(), currentPass()->getFboId()); + + prepareCmpTask(task, 1.f); + + // matrix buffer + { + float matrix[16]; + memset(matrix, 0, 16 * sizeof(float)); + matrix[0] = 1.f; + matrix[5] = 1.f; + matrix[10] = 1.f; + matrix[15] = 1.f; + uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); + + task->addBindResource(GlBindingResource{ + 0, + loc, + mGpuBuffer->getBufferId(), + mGpuBuffer->push(matrix, 16 * sizeof(float), true), + 16 * sizeof(float), + }); + } + // image info + { + uint32_t info[4] = {ABGR8888, 0, cmp->opacity, 0}; + uint32_t loc = task->getProgram()->getUniformBlockIndex("ColorInfo"); + + task->addBindResource(GlBindingResource{ + 1, + loc, + mGpuBuffer->getBufferId(), + mGpuBuffer->push(info, 4 * sizeof(uint32_t), true), + 4 * sizeof(uint32_t), + }); + } + // texture id + { + uint32_t loc = task->getProgram()->getUniformLocation("uTexture"); + task->addBindResource(GlBindingResource{0, renderPass.getTextureId(), loc}); + } + + currentPass()->addRenderTask(std::move(task)); } - - auto renderPass = std::move(mRenderPassStack.back()); - mRenderPassStack.pop_back(); - - auto task = renderPass.endRenderPass( - mPrograms[RT_Image].get(), currentPass()->getFboId()); - - prepareCmpTask(task); - - // matrix buffer - { - float matrix[16]; - memset(matrix, 0, 16 * sizeof(float)); - matrix[0] = 1.f; - matrix[5] = 1.f; - matrix[10] = 1.f; - matrix[15] = 1.f; - uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); - - task->addBindResource(GlBindingResource{ - 0, - loc, - mGpuBuffer->getBufferId(), - mGpuBuffer->push(matrix, 16 * sizeof(float), true), - 16 * sizeof(float), - }); - } - // image info - { - uint32_t info[4] = {ABGR8888, 0, cmp->opacity, 0}; - uint32_t loc = task->getProgram()->getUniformBlockIndex("ColorInfo"); - - task->addBindResource(GlBindingResource{ - 1, - loc, - mGpuBuffer->getBufferId(), - mGpuBuffer->push(info, 4 * sizeof(uint32_t), true), - 4 * sizeof(uint32_t), - }); - } - // texture id - { - uint32_t loc = task->getProgram()->getUniformLocation("uTexture"); - task->addBindResource(GlBindingResource{0, renderPass.getFboId(), loc}); - } - - currentPass()->addRenderTask(std::move(task)); } diff --git a/src/renderer/gl_engine/tvgGlRenderer.h b/src/renderer/gl_engine/tvgGlRenderer.h index cff97d78..9be1092d 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.h +++ b/src/renderer/gl_engine/tvgGlRenderer.h @@ -38,6 +38,14 @@ public: RT_LinGradient, RT_RadGradient, RT_Image, + RT_MaskAlpha, + RT_MaskAlphaInv, + RT_MaskLuma, + RT_MaskLumaInv, + RT_MaskAdd, + RT_MaskSub, + RT_MaskIntersect, + RT_MaskDifference, RT_None, }; @@ -81,7 +89,7 @@ private: GlRenderPass* currentPass(); - void prepareCmpTask(GlRenderTask* task); + void prepareCmpTask(GlRenderTask* task, float opacity); void endRenderPass(Compositor* cmp); GLint mTargetFboId = 0; diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.cpp b/src/renderer/gl_engine/tvgGlShaderSrc.cpp index 60562b94..1bc30997 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.cpp +++ b/src/renderer/gl_engine/tvgGlShaderSrc.cpp @@ -252,3 +252,175 @@ const char* IMAGE_FRAG_SHADER = TVG_COMPOSE_SHADER( FragColor = vec4(result.rgb, result.a * opacity * aOpacity); \n } \n ); + +const char* MASK_VERT_SHADER = TVG_COMPOSE_SHADER( +layout(location = 0) in vec3 aLocation; \n +layout(location = 1) in vec2 aUV; \n + \n +out float vOpacity; \n +out vec2 vUV; \n + \n +void main() { \n + vUV = aUV; \n + vOpacity = aLocation.z; \n + \n + gl_Position = vec4(aLocation.xy, 0.0, 1.0); \n +} \n +); + + +const char* MASK_ALPHA_FRAG_SHADER = TVG_COMPOSE_SHADER( +uniform sampler2D uSrcTexture; \n +uniform sampler2D uMaskTexture; \n + \n +in float vOpacity; \n +in vec2 vUV; \n + \n +out vec4 FragColor; \n + \n +void main() { \n + vec4 srcColor = texture(uSrcTexture, vUV); \n + vec4 maskColor = texture(uMaskTexture, vUV); \n + \n + FragColor = vec4(srcColor.rgb, \n + srcColor.a * maskColor.a * vOpacity); \n +} \n +); + +const char* MASK_INV_ALPHA_FRAG_SHADER = TVG_COMPOSE_SHADER( +uniform sampler2D uSrcTexture; \n +uniform sampler2D uMaskTexture; \n + \n +in float vOpacity; \n +in vec2 vUV; \n + \n +out vec4 FragColor; \n + \n +void main() { \n + vec4 srcColor = texture(uSrcTexture, vUV); \n + vec4 maskColor = texture(uMaskTexture, vUV); \n + \n + FragColor = vec4(srcColor.rgb, \n + srcColor.a * (1.0 - maskColor.a) * vOpacity); \n +} \n +); + +const char* MASK_LUMA_FRAG_SHADER = TVG_COMPOSE_SHADER( +uniform sampler2D uSrcTexture; \n +uniform sampler2D uMaskTexture; \n + \n +in float vOpacity; \n +in vec2 vUV; \n + \n +out vec4 FragColor; \n + \n +void main() { \n + vec4 srcColor = texture(uSrcTexture, vUV); \n + vec4 maskColor = texture(uMaskTexture, vUV); \n + \n + FragColor = srcColor * vOpacity * (0.299 * maskColor.r + 0.587 * maskColor.g + 0.114 * maskColor.b); \n +} \n +); + +const char* MASK_INV_LUMA_FRAG_SHADER = TVG_COMPOSE_SHADER( +uniform sampler2D uSrcTexture; \n +uniform sampler2D uMaskTexture; \n + \n +in float vOpacity; \n +in vec2 vUV; \n + \n +out vec4 FragColor; \n + \n +void main() { \n + vec4 srcColor = texture(uSrcTexture, vUV); \n + vec4 maskColor = texture(uMaskTexture, vUV); \n + \n + float luma = (0.299 * maskColor.r + 0.587 * maskColor.g + 0.114 * maskColor.b); \n + FragColor = srcColor * vOpacity * (1.0 - luma); \n +} \n +); + +const char* MASK_ADD_FRAG_SHADER = TVG_COMPOSE_SHADER( +uniform sampler2D uSrcTexture; \n +uniform sampler2D uMaskTexture; \n + \n +in float vOpacity; \n +in vec2 vUV; \n + \n +out vec4 FragColor; \n + \n +void main() { \n + vec4 srcColor = texture(uSrcTexture, vUV); \n + vec4 maskColor = texture(uMaskTexture, vUV); \n + \n + vec4 color = srcColor + maskColor * (1.0 - srcColor.a); \n + \n + FragColor = min(color, vec4(1.0, 1.0, 1.0, 1.0 * vOpacity)) ; \n +} \n +); + +const char* MASK_SUB_FRAG_SHADER = TVG_COMPOSE_SHADER( +uniform sampler2D uSrcTexture; \n +uniform sampler2D uMaskTexture; \n + \n +in float vOpacity; \n +in vec2 vUV; \n + \n +out vec4 FragColor; \n + \n +void main() { \n + vec4 srcColor = texture(uSrcTexture, vUV); \n + vec4 maskColor = texture(uMaskTexture, vUV); \n + float a = srcColor.a - maskColor.a; \n + \n + if (a <= 0.0) { \n + FragColor = vec4(0.0, 0.0, 0.0, 0.0); \n + } else { \n + FragColor = vec4(srcColor.rgb, srcColor.a * vOpacity * a); \n + } \n +} \n +); + +const char* MASK_INTERSECT_FRAG_SHADER = TVG_COMPOSE_SHADER( +uniform sampler2D uSrcTexture; \n +uniform sampler2D uMaskTexture; \n + \n +in float vOpacity; \n +in vec2 vUV; \n + \n +out vec4 FragColor; \n + \n +void main() { \n + vec4 srcColor = texture(uSrcTexture, vUV); \n + vec4 maskColor = texture(uMaskTexture, vUV); \n + \n + float intAlpha = srcColor.a * maskColor.a; \n + \n + FragColor = vec4(maskColor.rgb, maskColor.a * vOpacity * intAlpha); \n +} \n +); + +const char* MASK_DIFF_FRAG_SHADER = TVG_COMPOSE_SHADER( +uniform sampler2D uSrcTexture; \n +uniform sampler2D uMaskTexture; \n + \n +in float vOpacity; \n +in vec2 vUV; \n + \n +out vec4 FragColor; \n + \n +void main() { \n + vec4 srcColor = texture(uSrcTexture, vUV); \n + vec4 maskColor = texture(uMaskTexture, vUV); \n + \n + float da = srcColor.a - maskColor.a; \n + \n + if (da == 0.0) { \n + FragColor = vec4(0.0, 0.0, 0.0, 0.0); \n + } else if (da > 0.0) { \n + FragColor = vec4(srcColor.rgb, srcColor.a * da * vOpacity); \n + } else { \n + FragColor = vec4(maskColor.rgb, maskColor.a * (-da) * vOpacity);\n + } \n +} \n +); \ No newline at end of file diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.h b/src/renderer/gl_engine/tvgGlShaderSrc.h index 5959559d..775c61ee 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.h +++ b/src/renderer/gl_engine/tvgGlShaderSrc.h @@ -30,5 +30,14 @@ extern const char* LINEAR_GRADIENT_FRAG_SHADER; extern const char* RADIAL_GRADIENT_FRAG_SHADER; extern const char* IMAGE_VERT_SHADER; extern const char* IMAGE_FRAG_SHADER; +extern const char* MASK_VERT_SHADER; +extern const char* MASK_ALPHA_FRAG_SHADER; +extern const char* MASK_INV_ALPHA_FRAG_SHADER; +extern const char* MASK_LUMA_FRAG_SHADER; +extern const char* MASK_INV_LUMA_FRAG_SHADER; +extern const char* MASK_ADD_FRAG_SHADER; +extern const char* MASK_SUB_FRAG_SHADER; +extern const char* MASK_INTERSECT_FRAG_SHADER; +extern const char* MASK_DIFF_FRAG_SHADER; #endif /* _TVG_GL_SHADERSRC_H_ */