diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index 2ff8fba9..3b74b2c9 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -31,6 +31,9 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ + +#define NOISE_LEVEL 0.5f + static int32_t initEngineCnt = false; static int32_t rendererCnt = 0; @@ -51,11 +54,689 @@ void GlRenderer::clearDisposes() } } + +GlRenderer::GlRenderer() :mGpuBuffer(new GlStageBuffer), mPrograms(), mComposePool() +{ +} + + +GlRenderer::~GlRenderer() +{ + for (uint32_t i = 0; i < mComposePool.count; i++) { + if (mComposePool[i]) delete mComposePool[i]; + } + + --rendererCnt; + + if (rendererCnt == 0 && initEngineCnt == 0) _termEngine(); +} + + +void GlRenderer::initShaders() +{ + // Solid Color Renderer + mPrograms.push_back(make_unique(GlShader::gen(COLOR_VERT_SHADER, COLOR_FRAG_SHADER))); + + // Linear Gradient Renderer + mPrograms.push_back(make_unique(GlShader::gen(GRADIENT_VERT_SHADER, LINEAR_GRADIENT_FRAG_SHADER))); + + // Radial Gradient Renderer + mPrograms.push_back(make_unique(GlShader::gen(GRADIENT_VERT_SHADER, RADIAL_GRADIENT_FRAG_SHADER))); + + // 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))); + // stencil Renderer + mPrograms.push_back(make_unique(GlShader::gen(STENCIL_VERT_SHADER, STENCIL_FRAG_SHADER))); + // blit Renderer + mPrograms.push_back(make_unique(GlShader::gen(BLIT_VERT_SHADER, BLIT_FRAG_SHADER))); +} + + +void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag, int32_t depth) +{ + const auto& vp = currentPass()->getViewport(); + auto bbox = sdata.geometry->getViewport(); + + bbox.intersect(vp); + + auto x = bbox.x - vp.x; + auto y = bbox.y - vp.y; + auto w = bbox.w; + auto h = bbox.h; + + auto task = new GlRenderTask(mPrograms[RT_Color].get()); + task->setDrawDepth(depth); + + if (!sdata.geometry->draw(task, mGpuBuffer.get(), flag)) { + delete task; + return; + } + + task->setViewport(RenderRegion { + x, + vp.h - y - h, + w, + h + }); + + GlRenderTask* stencilTask = nullptr; + + GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag); + if (stencilMode != GlStencilMode::None) { + stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task); + stencilTask->setDrawDepth(depth); + } + + a = MULTIPLY(a, sdata.opacity); + + if (flag & RenderUpdateFlag::Stroke) { + float strokeWidth = sdata.rshape->strokeWidth(); + if (strokeWidth < MIN_GL_STROKE_WIDTH) { + float alpha = strokeWidth / MIN_GL_STROKE_WIDTH; + a = MULTIPLY(a, static_cast(alpha * 255)); + } + } + + // matrix buffer + { + const auto& matrix = sdata.geometry->getTransformMatrix(); + + float matrix44[16]; + + currentPass()->getMatrix(matrix44, matrix); + + uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); + + uint32_t viewOffset = mGpuBuffer->push(matrix44, 16 * sizeof(float), true); + + task->addBindResource(GlBindingResource{ + 0, + loc, + mGpuBuffer->getBufferId(), + viewOffset, + 16 * sizeof(float), + }); + + if (stencilTask) { + stencilTask->addBindResource(GlBindingResource{ + 0, + static_cast(stencilTask->getProgram()->getUniformBlockIndex("Matrix")), + mGpuBuffer->getBufferId(), + viewOffset, + 16 * sizeof(float), + }); + } + } + // color + { + float color[4] = {r / 255.f, g / 255.f, b / 255.f, a / 255.f}; + + uint32_t loc = task->getProgram()->getUniformBlockIndex("ColorInfo"); + + task->addBindResource(GlBindingResource{ + 1, + loc, + mGpuBuffer->getBufferId(), + mGpuBuffer->push(color, 4 * sizeof(float), true), + 4 * sizeof(float), + }); + } + + if (stencilTask) { + currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task, stencilMode)); + } else { + currentPass()->addRenderTask(task); + } +} + + +void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag, int32_t depth) +{ + + const auto& vp = currentPass()->getViewport(); + auto bbox = sdata.geometry->getViewport(); + + bbox.intersect(vp); + + const Fill::ColorStop* stops = nullptr; + auto stopCnt = min(fill->colorStops(&stops), + static_cast(MAX_GRADIENT_STOPS)); + if (stopCnt < 2) return; + + GlRenderTask* task = nullptr; + + if (fill->identifier() == TVG_CLASS_ID_LINEAR) { + task = new GlRenderTask(mPrograms[RT_LinGradient].get()); + } else if (fill->identifier() == TVG_CLASS_ID_RADIAL) { + task = new GlRenderTask(mPrograms[RT_RadGradient].get()); + } else { + return; + } + + task->setDrawDepth(depth); + + if (!sdata.geometry->draw(task, mGpuBuffer.get(), flag)) { + delete task; + return; + } + + auto x = bbox.x - vp.x; + auto y = bbox.y - vp.y; + + task->setViewport(RenderRegion { + x, + vp.h - y - bbox.h, + bbox.w, + bbox.h + }); + + GlRenderTask* stencilTask = nullptr; + GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag); + if (stencilMode != GlStencilMode::None) { + stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task); + stencilTask->setDrawDepth(depth); + } + + // matrix buffer + { + const auto& matrix = sdata.geometry->getTransformMatrix(); + + auto gradientTransform = fill->transform(); + float invMat4[16]; + if (!mathIdentity(const_cast(&gradientTransform))) { + Matrix inv{}; + mathInverse(&gradientTransform , &inv); + + GET_MATRIX44(inv, invMat4); + } else { + memset(invMat4, 0, 16 * sizeof(float)); + invMat4[0] = 1.f; + invMat4[5] = 1.f; + invMat4[10] = 1.f; + invMat4[15] = 1.f; + } + + float matrix44[16]; + + currentPass()->getMatrix(matrix44, matrix); + + uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); + + uint32_t viewOffset = mGpuBuffer->push(matrix44, 16 * sizeof(float), true); + + task->addBindResource(GlBindingResource{ + 0, + loc, + mGpuBuffer->getBufferId(), + viewOffset, + 16 * sizeof(float), + }); + + if (stencilTask) { + stencilTask->addBindResource(GlBindingResource{ + 0, + static_cast(stencilTask->getProgram()->getUniformBlockIndex("Matrix")), + mGpuBuffer->getBufferId(), + viewOffset, + 16 * sizeof(float), + }); + } + + loc = task->getProgram()->getUniformBlockIndex("InvMatrix"); + viewOffset = mGpuBuffer->push(invMat4, 16 * sizeof(float), true); + + task->addBindResource(GlBindingResource{ + 1, + loc, + mGpuBuffer->getBufferId(), + viewOffset, + 16 * sizeof(float), + }); + } + + float alpha = 1.0f; + + if (flag & RenderUpdateFlag::GradientStroke) { + float strokeWidth = sdata.rshape->strokeWidth(); + if (strokeWidth < MIN_GL_STROKE_WIDTH) { + alpha = strokeWidth / MIN_GL_STROKE_WIDTH; + } + } + + // gradient block + { + GlBindingResource gradientBinding{}; + uint32_t loc = task->getProgram()->getUniformBlockIndex("GradientInfo"); + + if (fill->identifier() == TVG_CLASS_ID_LINEAR) { + auto linearFill = static_cast(fill); + + GlLinearGradientBlock gradientBlock; + + gradientBlock.nStops[1] = NOISE_LEVEL; + gradientBlock.nStops[2] = static_cast(fill->spread()) * 1.f; + uint32_t nStops = 0; + for (uint32_t i = 0; i < stopCnt; ++i) { + if (i > 0 && gradientBlock.stopPoints[nStops - 1] > stops[i].offset) continue; + + gradientBlock.stopPoints[i] = stops[i].offset; + gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f; + gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f; + gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f; + gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f * alpha; + nStops++; + } + gradientBlock.nStops[0] = nStops * 1.f; + + float x1, x2, y1, y2; + linearFill->linear(&x1, &y1, &x2, &y2); + + gradientBlock.startPos[0] = x1; + gradientBlock.startPos[1] = y1; + gradientBlock.stopPos[0] = x2; + gradientBlock.stopPos[1] = y2; + + gradientBinding = GlBindingResource{ + 2, + loc, + mGpuBuffer->getBufferId(), + mGpuBuffer->push(&gradientBlock, sizeof(GlLinearGradientBlock), true), + sizeof(GlLinearGradientBlock), + }; + } else { + auto radialFill = static_cast(fill); + + GlRadialGradientBlock gradientBlock; + + gradientBlock.nStops[1] = NOISE_LEVEL; + gradientBlock.nStops[2] = static_cast(fill->spread()) * 1.f; + + uint32_t nStops = 0; + for (uint32_t i = 0; i < stopCnt; ++i) { + if (i > 0 && gradientBlock.stopPoints[nStops - 1] > stops[i].offset) continue; + + gradientBlock.stopPoints[i] = stops[i].offset; + gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f; + gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f; + gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f; + gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f * alpha; + nStops++; + } + gradientBlock.nStops[0] = nStops * 1.f; + + float x, y, r; + radialFill->radial(&x, &y, &r); + + gradientBlock.centerPos[0] = x; + gradientBlock.centerPos[1] = y; + gradientBlock.radius[0] = r; + + gradientBinding = GlBindingResource{ + 2, + loc, + mGpuBuffer->getBufferId(), + mGpuBuffer->push(&gradientBlock, sizeof(GlRadialGradientBlock), true), + sizeof(GlRadialGradientBlock), + }; + } + + task->addBindResource(gradientBinding); + } + + if (stencilTask) { + currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task, stencilMode)); + } else { + currentPass()->addRenderTask(task); + } +} + + +void GlRenderer::drawClip(Array& clips) +{ + Array identityVertex(4 * 2); + float left = -1.f; + float top = 1.f; + float right = 1.f; + float bottom = -1.f; + + identityVertex.push(left); + identityVertex.push(top); + identityVertex.push(left); + identityVertex.push(bottom); + identityVertex.push(right); + identityVertex.push(top); + identityVertex.push(right); + identityVertex.push(bottom); + + Array identityIndex(6); + identityIndex.push(0); + identityIndex.push(1); + identityIndex.push(2); + identityIndex.push(2); + identityIndex.push(1); + identityIndex.push(3); + + float mat4[16]; + memset(mat4, 0, sizeof(float) * 16); + mat4[0] = 1.f; + mat4[5] = 1.f; + mat4[10] = 1.f; + mat4[15] = 1.f; + + auto identityVertexOffset = mGpuBuffer->push(identityVertex.data, 8 * sizeof(float)); + auto identityIndexOffset = mGpuBuffer->push(identityIndex.data, 6 * sizeof(uint32_t)); + auto mat4Offset = mGpuBuffer->push(mat4, 16 * sizeof(float), true); + + Array clipDepths(clips.count); + clipDepths.count = clips.count; + + for (int32_t i = clips.count - 1; i >= 0; i--) { + clipDepths[i] = currentPass()->nextDrawDepth(); + } + + const auto& vp = currentPass()->getViewport(); + + for (uint32_t i = 0; i < clips.count; ++i) { + auto sdata = static_cast(clips[i]); + + auto clipTask = new GlRenderTask(mPrograms[RT_Stencil].get()); + + clipTask->setDrawDepth(clipDepths[i]); + + sdata->geometry->draw(clipTask, mGpuBuffer.get(), RenderUpdateFlag::Path); + + auto bbox = sdata->geometry->getViewport(); + + bbox.intersect(vp); + + auto x = bbox.x - vp.x; + auto y = bbox.y - vp.y; + + clipTask->setViewport(RenderRegion { + x, + vp.h - y - bbox.h, + bbox.w, + bbox.h, + }); + + const auto& matrix = sdata->geometry->getTransformMatrix(); + + float matrix44[16]; + + currentPass()->getMatrix(matrix44, matrix); + + uint32_t loc = clipTask->getProgram()->getUniformBlockIndex("Matrix"); + + uint32_t viewOffset = mGpuBuffer->push(matrix44, 16 * sizeof(float), true); + + clipTask->addBindResource(GlBindingResource{ + 0, + loc, + mGpuBuffer->getBufferId(), + viewOffset, + 16 * sizeof(float), + }); + + auto maskTask = new GlRenderTask(mPrograms[RT_Stencil].get()); + + maskTask->setDrawDepth(clipDepths[i]); + + maskTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), identityVertexOffset}); + maskTask->addBindResource(GlBindingResource{ + 0, + loc, + mGpuBuffer->getBufferId(), + mat4Offset, 16 * sizeof(float), + }); + + maskTask->setDrawRange(identityIndexOffset, 6); + maskTask->setViewport(RenderRegion{0, 0, static_cast(vp.w), static_cast(vp.h)}); + + currentPass()->addRenderTask(new GlClipTask(clipTask, maskTask)); + } +} + +GlRenderPass* GlRenderer::currentPass() +{ + if (mRenderPassStack.empty()) return nullptr; + + return &mRenderPassStack.back(); +} + + +void GlRenderer::prepareBlitTask(GlBlitTask* task) +{ + RenderRegion region{0, 0, static_cast(surface.w), static_cast(surface.h)}; + prepareCmpTask(task, region, surface.w, surface.h); + + { + uint32_t loc = task->getProgram()->getUniformLocation("uSrcTexture"); + task->addBindResource(GlBindingResource{0, task->getColorTexture(), loc}); + } +} + + +void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint32_t cmpWidth, uint32_t cmpHeight) +{ + // we use 1:1 blit mapping since compositor fbo is same size as root fbo + Array vertices(4 * 4); + + const auto& passVp = currentPass()->getViewport(); + + auto taskVp = vp; + taskVp.intersect(passVp); + + auto x = taskVp.x - passVp.x; + auto y = taskVp.y - passVp.y; + auto w = taskVp.w; + auto h = taskVp.h; + + float rw = static_cast(passVp.w); + float rh = static_cast(passVp.h); + + float l = static_cast(x); + float t = static_cast(rh - y); + float r = static_cast(x + w); + float b = static_cast(rh - y - h); + + // map vp ltrp to -1:1 + float left = (l / rw) * 2.f - 1.f; + float top = (t / rh) * 2.f - 1.f; + float right = (r / rw) * 2.f - 1.f; + float bottom = (b / rh) * 2.f - 1.f; + + float uw = static_cast(w) / static_cast(cmpWidth); + float uh = static_cast(h) / static_cast(cmpHeight); + + // left top point + vertices.push(left); + vertices.push(top); + vertices.push(0.f); + vertices.push(uh); + // left bottom point + vertices.push(left); + vertices.push(bottom); + vertices.push(0.f); + vertices.push(0.f); + // right top point + vertices.push(right); + vertices.push(top); + vertices.push(uw); + vertices.push(uh); + // right bottom point + vertices.push(right); + vertices.push(bottom); + vertices.push(uw); + vertices.push(0.f); + + 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->push(indices.data, indices.count * sizeof(uint32_t)); + + task->addVertexLayout(GlVertexLayout{0, 2, 4 * sizeof(float), vertexOffset}); + task->addVertexLayout(GlVertexLayout{1, 2, 4 * sizeof(float), vertexOffset + 2 * sizeof(float)}); + + task->setDrawRange(indexOffset, indices.count); + + task->setViewport(RenderRegion{ + x, + static_cast((passVp.h - y - h)), + w, + h, + }); +} + + +void GlRenderer::endRenderPass(Compositor* cmp) +{ + auto gl_cmp = static_cast(cmp); + if (cmp->method != CompositeMethod::None) { + auto self_pass = std::move(mRenderPassStack.back()); + mRenderPassStack.pop_back(); + + // mask is pushed first + auto mask_pass = std::move(mRenderPassStack.back()); + mRenderPassStack.pop_back(); + + if (self_pass.isEmpty() || mask_pass.isEmpty()) return; + + 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()); + prev_task->setDrawDepth(currentPass()->nextDrawDepth()); + prev_task->setRenderSize(static_cast(gl_cmp->bbox.w), static_cast(gl_cmp->bbox.h)); + prev_task->setViewport(gl_cmp->bbox); + + auto compose_task = self_pass.endRenderPass(program, currentPass()->getFboId()); + compose_task->setRenderSize(static_cast(gl_cmp->bbox.w), static_cast(gl_cmp->bbox.h)); + compose_task->setPrevTask(prev_task); + + prepareCmpTask(compose_task, gl_cmp->bbox, self_pass.getFboWidth(), self_pass.getFboHeight()); + + { + 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}); + } + + compose_task->setDrawDepth(currentPass()->nextDrawDepth()); + compose_task->setParentSize(static_cast(currentPass()->getViewport().w), static_cast(currentPass()->getViewport().h)); + currentPass()->addRenderTask(compose_task); + } else { + + auto renderPass = std::move(mRenderPassStack.back()); + mRenderPassStack.pop_back(); + + if (renderPass.isEmpty()) return; + + auto task = renderPass.endRenderPass( + mPrograms[RT_Image].get(), currentPass()->getFboId()); + task->setRenderSize(static_cast(gl_cmp->bbox.w), static_cast(gl_cmp->bbox.h)); + prepareCmpTask(task, gl_cmp->bbox, renderPass.getFboWidth(), renderPass.getFboHeight()); + task->setDrawDepth(currentPass()->nextDrawDepth()); + + // 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}); + } + task->setParentSize(static_cast(currentPass()->getViewport().w), static_cast(currentPass()->getViewport().h)); + currentPass()->addRenderTask(std::move(task)); + } +} + + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -#define NOISE_LEVEL 0.5f bool GlRenderer::clear() { @@ -425,6 +1106,7 @@ static GLuint _genTexture(Surface* image) return tex; } + RenderData GlRenderer::prepare(Surface* image, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) { if (flags == RenderUpdateFlag::None) return data; @@ -573,677 +1255,4 @@ GlRenderer* GlRenderer::gen() TVGLOG("GL_ENGINE", "OpenGL/ES version = v%d.%d", vMajor, vMinor); return new GlRenderer(); -} - - -GlRenderer::GlRenderer() :mGpuBuffer(new GlStageBuffer), mPrograms(), mComposePool() -{ -} - - -GlRenderer::~GlRenderer() -{ - for (uint32_t i = 0; i < mComposePool.count; i++) { - if (mComposePool[i]) delete mComposePool[i]; - } - - --rendererCnt; - - if (rendererCnt == 0 && initEngineCnt == 0) _termEngine(); -} - - -void GlRenderer::initShaders() -{ - // Solid Color Renderer - mPrograms.push_back(make_unique(GlShader::gen(COLOR_VERT_SHADER, COLOR_FRAG_SHADER))); - - // Linear Gradient Renderer - mPrograms.push_back(make_unique(GlShader::gen(GRADIENT_VERT_SHADER, LINEAR_GRADIENT_FRAG_SHADER))); - - // Radial Gradient Renderer - mPrograms.push_back(make_unique(GlShader::gen(GRADIENT_VERT_SHADER, RADIAL_GRADIENT_FRAG_SHADER))); - - // 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))); - // stencil Renderer - mPrograms.push_back(make_unique(GlShader::gen(STENCIL_VERT_SHADER, STENCIL_FRAG_SHADER))); - // blit Renderer - mPrograms.push_back(make_unique(GlShader::gen(BLIT_VERT_SHADER, BLIT_FRAG_SHADER))); -} - - -void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag, int32_t depth) -{ - const auto& vp = currentPass()->getViewport(); - auto bbox = sdata.geometry->getViewport(); - - bbox.intersect(vp); - - auto x = bbox.x - vp.x; - auto y = bbox.y - vp.y; - auto w = bbox.w; - auto h = bbox.h; - - auto task = new GlRenderTask(mPrograms[RT_Color].get()); - task->setDrawDepth(depth); - - if (!sdata.geometry->draw(task, mGpuBuffer.get(), flag)) { - delete task; - return; - } - - task->setViewport(RenderRegion { - x, - vp.h - y - h, - w, - h - }); - - GlRenderTask* stencilTask = nullptr; - - GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag); - if (stencilMode != GlStencilMode::None) { - stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task); - stencilTask->setDrawDepth(depth); - } - - a = MULTIPLY(a, sdata.opacity); - - if (flag & RenderUpdateFlag::Stroke) { - float strokeWidth = sdata.rshape->strokeWidth(); - if (strokeWidth < MIN_GL_STROKE_WIDTH) { - float alpha = strokeWidth / MIN_GL_STROKE_WIDTH; - a = MULTIPLY(a, static_cast(alpha * 255)); - } - } - - // matrix buffer - { - const auto& matrix = sdata.geometry->getTransformMatrix(); - - float matrix44[16]; - - currentPass()->getMatrix(matrix44, matrix); - - uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); - - uint32_t viewOffset = mGpuBuffer->push(matrix44, 16 * sizeof(float), true); - - task->addBindResource(GlBindingResource{ - 0, - loc, - mGpuBuffer->getBufferId(), - viewOffset, - 16 * sizeof(float), - }); - - if (stencilTask) { - stencilTask->addBindResource(GlBindingResource{ - 0, - static_cast(stencilTask->getProgram()->getUniformBlockIndex("Matrix")), - mGpuBuffer->getBufferId(), - viewOffset, - 16 * sizeof(float), - }); - } - } - // color - { - float color[4] = {r / 255.f, g / 255.f, b / 255.f, a / 255.f}; - - uint32_t loc = task->getProgram()->getUniformBlockIndex("ColorInfo"); - - task->addBindResource(GlBindingResource{ - 1, - loc, - mGpuBuffer->getBufferId(), - mGpuBuffer->push(color, 4 * sizeof(float), true), - 4 * sizeof(float), - }); - } - - if (stencilTask) { - currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task, stencilMode)); - } else { - currentPass()->addRenderTask(task); - } -} - - -void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag, int32_t depth) -{ - - const auto& vp = currentPass()->getViewport(); - auto bbox = sdata.geometry->getViewport(); - - bbox.intersect(vp); - - const Fill::ColorStop* stops = nullptr; - auto stopCnt = min(fill->colorStops(&stops), - static_cast(MAX_GRADIENT_STOPS)); - if (stopCnt < 2) return; - - GlRenderTask* task = nullptr; - - if (fill->identifier() == TVG_CLASS_ID_LINEAR) { - task = new GlRenderTask(mPrograms[RT_LinGradient].get()); - } else if (fill->identifier() == TVG_CLASS_ID_RADIAL) { - task = new GlRenderTask(mPrograms[RT_RadGradient].get()); - } else { - return; - } - - task->setDrawDepth(depth); - - if (!sdata.geometry->draw(task, mGpuBuffer.get(), flag)) { - delete task; - return; - } - - auto x = bbox.x - vp.x; - auto y = bbox.y - vp.y; - - task->setViewport(RenderRegion { - x, - vp.h - y - bbox.h, - bbox.w, - bbox.h - }); - - GlRenderTask* stencilTask = nullptr; - GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag); - if (stencilMode != GlStencilMode::None) { - stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task); - stencilTask->setDrawDepth(depth); - } - - // matrix buffer - { - const auto& matrix = sdata.geometry->getTransformMatrix(); - - auto gradientTransform = fill->transform(); - float invMat4[16]; - if (!mathIdentity(const_cast(&gradientTransform))) { - Matrix inv{}; - mathInverse(&gradientTransform , &inv); - - GET_MATRIX44(inv, invMat4); - } else { - memset(invMat4, 0, 16 * sizeof(float)); - invMat4[0] = 1.f; - invMat4[5] = 1.f; - invMat4[10] = 1.f; - invMat4[15] = 1.f; - } - - float matrix44[16]; - - currentPass()->getMatrix(matrix44, matrix); - - uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); - - uint32_t viewOffset = mGpuBuffer->push(matrix44, 16 * sizeof(float), true); - - task->addBindResource(GlBindingResource{ - 0, - loc, - mGpuBuffer->getBufferId(), - viewOffset, - 16 * sizeof(float), - }); - - if (stencilTask) { - stencilTask->addBindResource(GlBindingResource{ - 0, - static_cast(stencilTask->getProgram()->getUniformBlockIndex("Matrix")), - mGpuBuffer->getBufferId(), - viewOffset, - 16 * sizeof(float), - }); - } - - loc = task->getProgram()->getUniformBlockIndex("InvMatrix"); - viewOffset = mGpuBuffer->push(invMat4, 16 * sizeof(float), true); - - task->addBindResource(GlBindingResource{ - 1, - loc, - mGpuBuffer->getBufferId(), - viewOffset, - 16 * sizeof(float), - }); - } - - float alpha = 1.0f; - - if (flag & RenderUpdateFlag::GradientStroke) { - float strokeWidth = sdata.rshape->strokeWidth(); - if (strokeWidth < MIN_GL_STROKE_WIDTH) { - alpha = strokeWidth / MIN_GL_STROKE_WIDTH; - } - } - - // gradient block - { - GlBindingResource gradientBinding{}; - uint32_t loc = task->getProgram()->getUniformBlockIndex("GradientInfo"); - - if (fill->identifier() == TVG_CLASS_ID_LINEAR) { - auto linearFill = static_cast(fill); - - GlLinearGradientBlock gradientBlock; - - gradientBlock.nStops[1] = NOISE_LEVEL; - gradientBlock.nStops[2] = static_cast(fill->spread()) * 1.f; - uint32_t nStops = 0; - for (uint32_t i = 0; i < stopCnt; ++i) { - if (i > 0 && gradientBlock.stopPoints[nStops - 1] > stops[i].offset) continue; - - gradientBlock.stopPoints[i] = stops[i].offset; - gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f; - gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f; - gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f; - gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f * alpha; - nStops++; - } - gradientBlock.nStops[0] = nStops * 1.f; - - float x1, x2, y1, y2; - linearFill->linear(&x1, &y1, &x2, &y2); - - gradientBlock.startPos[0] = x1; - gradientBlock.startPos[1] = y1; - gradientBlock.stopPos[0] = x2; - gradientBlock.stopPos[1] = y2; - - gradientBinding = GlBindingResource{ - 2, - loc, - mGpuBuffer->getBufferId(), - mGpuBuffer->push(&gradientBlock, sizeof(GlLinearGradientBlock), true), - sizeof(GlLinearGradientBlock), - }; - } else { - auto radialFill = static_cast(fill); - - GlRadialGradientBlock gradientBlock; - - gradientBlock.nStops[1] = NOISE_LEVEL; - gradientBlock.nStops[2] = static_cast(fill->spread()) * 1.f; - - uint32_t nStops = 0; - for (uint32_t i = 0; i < stopCnt; ++i) { - if (i > 0 && gradientBlock.stopPoints[nStops - 1] > stops[i].offset) continue; - - gradientBlock.stopPoints[i] = stops[i].offset; - gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f; - gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f; - gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f; - gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f * alpha; - nStops++; - } - gradientBlock.nStops[0] = nStops * 1.f; - - float x, y, r; - radialFill->radial(&x, &y, &r); - - gradientBlock.centerPos[0] = x; - gradientBlock.centerPos[1] = y; - gradientBlock.radius[0] = r; - - gradientBinding = GlBindingResource{ - 2, - loc, - mGpuBuffer->getBufferId(), - mGpuBuffer->push(&gradientBlock, sizeof(GlRadialGradientBlock), true), - sizeof(GlRadialGradientBlock), - }; - } - - task->addBindResource(gradientBinding); - } - - if (stencilTask) { - currentPass()->addRenderTask(new GlStencilCoverTask(stencilTask, task, stencilMode)); - } else { - currentPass()->addRenderTask(task); - } -} - -void GlRenderer::drawClip(Array& clips) -{ - Array identityVertex(4 * 2); - float left = -1.f; - float top = 1.f; - float right = 1.f; - float bottom = -1.f; - - identityVertex.push(left); - identityVertex.push(top); - identityVertex.push(left); - identityVertex.push(bottom); - identityVertex.push(right); - identityVertex.push(top); - identityVertex.push(right); - identityVertex.push(bottom); - - Array identityIndex(6); - identityIndex.push(0); - identityIndex.push(1); - identityIndex.push(2); - identityIndex.push(2); - identityIndex.push(1); - identityIndex.push(3); - - float mat4[16]; - memset(mat4, 0, sizeof(float) * 16); - mat4[0] = 1.f; - mat4[5] = 1.f; - mat4[10] = 1.f; - mat4[15] = 1.f; - - auto identityVertexOffset = mGpuBuffer->push(identityVertex.data, 8 * sizeof(float)); - auto identityIndexOffset = mGpuBuffer->push(identityIndex.data, 6 * sizeof(uint32_t)); - auto mat4Offset = mGpuBuffer->push(mat4, 16 * sizeof(float), true); - - Array clipDepths(clips.count); - clipDepths.count = clips.count; - - for (int32_t i = clips.count - 1; i >= 0; i--) { - clipDepths[i] = currentPass()->nextDrawDepth(); - } - - const auto& vp = currentPass()->getViewport(); - - for (uint32_t i = 0; i < clips.count; ++i) { - auto sdata = static_cast(clips[i]); - - auto clipTask = new GlRenderTask(mPrograms[RT_Stencil].get()); - - clipTask->setDrawDepth(clipDepths[i]); - - sdata->geometry->draw(clipTask, mGpuBuffer.get(), RenderUpdateFlag::Path); - - auto bbox = sdata->geometry->getViewport(); - - bbox.intersect(vp); - - auto x = bbox.x - vp.x; - auto y = bbox.y - vp.y; - - clipTask->setViewport(RenderRegion { - x, - vp.h - y - bbox.h, - bbox.w, - bbox.h, - }); - - const auto& matrix = sdata->geometry->getTransformMatrix(); - - float matrix44[16]; - - currentPass()->getMatrix(matrix44, matrix); - - uint32_t loc = clipTask->getProgram()->getUniformBlockIndex("Matrix"); - - uint32_t viewOffset = mGpuBuffer->push(matrix44, 16 * sizeof(float), true); - - clipTask->addBindResource(GlBindingResource{ - 0, - loc, - mGpuBuffer->getBufferId(), - viewOffset, - 16 * sizeof(float), - }); - - auto maskTask = new GlRenderTask(mPrograms[RT_Stencil].get()); - - maskTask->setDrawDepth(clipDepths[i]); - - maskTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), identityVertexOffset}); - maskTask->addBindResource(GlBindingResource{ - 0, - loc, - mGpuBuffer->getBufferId(), - mat4Offset, 16 * sizeof(float), - }); - - maskTask->setDrawRange(identityIndexOffset, 6); - maskTask->setViewport(RenderRegion{0, 0, static_cast(vp.w), static_cast(vp.h)}); - - currentPass()->addRenderTask(new GlClipTask(clipTask, maskTask)); - } -} - -GlRenderPass* GlRenderer::currentPass() -{ - if (mRenderPassStack.empty()) return nullptr; - - return &mRenderPassStack.back(); -} - -void GlRenderer::prepareBlitTask(GlBlitTask* task) -{ - RenderRegion region{0, 0, static_cast(surface.w), static_cast(surface.h)}; - prepareCmpTask(task, region, surface.w, surface.h); - - { - uint32_t loc = task->getProgram()->getUniformLocation("uSrcTexture"); - task->addBindResource(GlBindingResource{0, task->getColorTexture(), loc}); - } -} - -void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint32_t cmpWidth, uint32_t cmpHeight) -{ - // we use 1:1 blit mapping since compositor fbo is same size as root fbo - Array vertices(4 * 4); - - const auto& passVp = currentPass()->getViewport(); - - auto taskVp = vp; - taskVp.intersect(passVp); - - auto x = taskVp.x - passVp.x; - auto y = taskVp.y - passVp.y; - auto w = taskVp.w; - auto h = taskVp.h; - - float rw = static_cast(passVp.w); - float rh = static_cast(passVp.h); - - float l = static_cast(x); - float t = static_cast(rh - y); - float r = static_cast(x + w); - float b = static_cast(rh - y - h); - - // map vp ltrp to -1:1 - float left = (l / rw) * 2.f - 1.f; - float top = (t / rh) * 2.f - 1.f; - float right = (r / rw) * 2.f - 1.f; - float bottom = (b / rh) * 2.f - 1.f; - - float uw = static_cast(w) / static_cast(cmpWidth); - float uh = static_cast(h) / static_cast(cmpHeight); - - // left top point - vertices.push(left); - vertices.push(top); - vertices.push(0.f); - vertices.push(uh); - // left bottom point - vertices.push(left); - vertices.push(bottom); - vertices.push(0.f); - vertices.push(0.f); - // right top point - vertices.push(right); - vertices.push(top); - vertices.push(uw); - vertices.push(uh); - // right bottom point - vertices.push(right); - vertices.push(bottom); - vertices.push(uw); - vertices.push(0.f); - - 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->push(indices.data, indices.count * sizeof(uint32_t)); - - task->addVertexLayout(GlVertexLayout{0, 2, 4 * sizeof(float), vertexOffset}); - task->addVertexLayout(GlVertexLayout{1, 2, 4 * sizeof(float), vertexOffset + 2 * sizeof(float)}); - - task->setDrawRange(indexOffset, indices.count); - - task->setViewport(RenderRegion{ - x, - static_cast((passVp.h - y - h)), - w, - h, - }); -} - -void GlRenderer::endRenderPass(Compositor* cmp) -{ - auto gl_cmp = static_cast(cmp); - if (cmp->method != CompositeMethod::None) { - auto self_pass = std::move(mRenderPassStack.back()); - mRenderPassStack.pop_back(); - - // mask is pushed first - auto mask_pass = std::move(mRenderPassStack.back()); - mRenderPassStack.pop_back(); - - if (self_pass.isEmpty() || mask_pass.isEmpty()) return; - - 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()); - prev_task->setDrawDepth(currentPass()->nextDrawDepth()); - prev_task->setRenderSize(static_cast(gl_cmp->bbox.w), static_cast(gl_cmp->bbox.h)); - prev_task->setViewport(gl_cmp->bbox); - - auto compose_task = self_pass.endRenderPass(program, currentPass()->getFboId()); - compose_task->setRenderSize(static_cast(gl_cmp->bbox.w), static_cast(gl_cmp->bbox.h)); - compose_task->setPrevTask(prev_task); - - prepareCmpTask(compose_task, gl_cmp->bbox, self_pass.getFboWidth(), self_pass.getFboHeight()); - - { - 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}); - } - - compose_task->setDrawDepth(currentPass()->nextDrawDepth()); - compose_task->setParentSize(static_cast(currentPass()->getViewport().w), static_cast(currentPass()->getViewport().h)); - currentPass()->addRenderTask(compose_task); - } else { - - auto renderPass = std::move(mRenderPassStack.back()); - mRenderPassStack.pop_back(); - - if (renderPass.isEmpty()) return; - - auto task = renderPass.endRenderPass( - mPrograms[RT_Image].get(), currentPass()->getFboId()); - task->setRenderSize(static_cast(gl_cmp->bbox.w), static_cast(gl_cmp->bbox.h)); - prepareCmpTask(task, gl_cmp->bbox, renderPass.getFboWidth(), renderPass.getFboHeight()); - task->setDrawDepth(currentPass()->nextDrawDepth()); - - // 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}); - } - task->setParentSize(static_cast(currentPass()->getViewport().w), static_cast(currentPass()->getViewport().h)); - currentPass()->addRenderTask(std::move(task)); - } -} +} \ No newline at end of file