From f8626d13d1ac9970ed3a7e3a62b6cd3aec92f384 Mon Sep 17 00:00:00 2001 From: RuiwenTang Date: Wed, 5 Jun 2024 19:55:31 +0800 Subject: [PATCH] gl_engine: fix clip path and bounds not correct * Optimize clip logical, change to use GL_GRATER and keep incrace depth value, so no need to do depth clear after every clip draw. * Correct geometry bounding box calculation, and make sure the bounds is larger than all vertices * Limit drawing area for off-screen RenderPass with correct scissor box --- src/renderer/gl_engine/tvgGlGeometry.cpp | 8 +-- src/renderer/gl_engine/tvgGlRenderPass.cpp | 6 +- src/renderer/gl_engine/tvgGlRenderPass.h | 11 ++- src/renderer/gl_engine/tvgGlRenderTask.cpp | 38 +++++++--- src/renderer/gl_engine/tvgGlRenderTask.h | 16 ++--- src/renderer/gl_engine/tvgGlRenderer.cpp | 77 ++++++++++++++++----- src/renderer/gl_engine/tvgGlRenderer.h | 4 +- src/renderer/gl_engine/tvgGlShaderSrc.cpp | 24 +++++-- src/renderer/gl_engine/tvgGlTessellator.cpp | 47 +++++++++---- 9 files changed, 166 insertions(+), 65 deletions(-) diff --git a/src/renderer/gl_engine/tvgGlGeometry.cpp b/src/renderer/gl_engine/tvgGlGeometry.cpp index 96d31f60..a64e7191 100644 --- a/src/renderer/gl_engine/tvgGlGeometry.cpp +++ b/src/renderer/gl_engine/tvgGlGeometry.cpp @@ -279,10 +279,10 @@ RenderRegion GlGeometry::getBounds() const float bottom = max(max(lt.y, lb.y), max(rt.y, rb.y)); auto bounds = RenderRegion { - static_cast(left), - static_cast(top), - static_cast(right - left), - static_cast(bottom - top), + static_cast(floor(left)), + static_cast(floor(top)), + static_cast(ceil(right - floor(left))), + static_cast(ceil(bottom - floor(top))), }; if (bounds.x < 0 || bounds.y < 0 || bounds.w < 0 || bounds.h < 0) { return mBounds; diff --git a/src/renderer/gl_engine/tvgGlRenderPass.cpp b/src/renderer/gl_engine/tvgGlRenderPass.cpp index 88c7b485..fbeaeeca 100644 --- a/src/renderer/gl_engine/tvgGlRenderPass.cpp +++ b/src/renderer/gl_engine/tvgGlRenderPass.cpp @@ -83,13 +83,15 @@ void GlRenderTarget::init(GLint resolveId) GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, resolveId)); } -GlRenderPass::GlRenderPass(GlRenderTarget* fbo): mFbo(fbo), mTasks() {} +GlRenderPass::GlRenderPass(GlRenderTarget* fbo): mFbo(fbo), mTasks(), mDrawDepth(0) {} -GlRenderPass::GlRenderPass(GlRenderPass&& other): mFbo(other.mFbo), mTasks() +GlRenderPass::GlRenderPass(GlRenderPass&& other): mFbo(other.mFbo), mTasks(), mDrawDepth(0) { mTasks.push(other.mTasks); other.mTasks.clear(); + + mDrawDepth = other.mDrawDepth; } GlRenderPass::~GlRenderPass() diff --git a/src/renderer/gl_engine/tvgGlRenderPass.h b/src/renderer/gl_engine/tvgGlRenderPass.h index 004d5de4..b2bc1d15 100644 --- a/src/renderer/gl_engine/tvgGlRenderPass.h +++ b/src/renderer/gl_engine/tvgGlRenderPass.h @@ -27,8 +27,8 @@ #include #include "tvgGlCommon.h" +#include "tvgGlRenderTask.h" -class GlRenderTask; class GlProgram; class GlRenderTarget @@ -72,11 +72,20 @@ public: template T* endRenderPass(GlProgram* program, GLuint targetFbo) { + int32_t maxDepth = mDrawDepth + 1; + + for (uint32_t i = 0; i < mTasks.count; i++) { + mTasks[i]->normalizeDrawDepth(maxDepth); + } + return new T(program, targetFbo, mFbo, std::move(mTasks)); } + + int nextDrawDepth() { return ++mDrawDepth; } private: GlRenderTarget* mFbo; Array mTasks = {}; + int32_t mDrawDepth = 0; }; diff --git a/src/renderer/gl_engine/tvgGlRenderTask.cpp b/src/renderer/gl_engine/tvgGlRenderTask.cpp index d6af01f1..ab417be7 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.cpp +++ b/src/renderer/gl_engine/tvgGlRenderTask.cpp @@ -41,6 +41,12 @@ void GlRenderTask::run() // bind shader mProgram->load(); + int32_t dLoc = mProgram->getUniformLocation("uDepth"); + if (dLoc >= 0) { + // fixme: prevent compiler warning: macro expands to multiple statements [-Wmultistatement-macros] + GL_CHECK(glUniform1f(dLoc, mDrawDepth)); + } + // setup scissor rect GL_CHECK(glScissor(mViewport.x, mViewport.y, mViewport.w, mViewport.h)); @@ -141,6 +147,12 @@ void GlStencilCoverTask::run() GL_CHECK(glDisable(GL_STENCIL_TEST)); } +void GlStencilCoverTask::normalizeDrawDepth(int32_t maxDepth) +{ + mCoverTask->normalizeDrawDepth(maxDepth); + mStencilTask->normalizeDrawDepth(maxDepth); +} + GlComposeTask::GlComposeTask(GlProgram* program, GLuint target, GlRenderTarget* fbo, Array&& tasks) :GlRenderTask(program) ,mTargetFbo(target), mFbo(fbo), mTasks() { @@ -162,11 +174,15 @@ void GlComposeTask::run() GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getSelfFbo())); GL_CHECK(glViewport(0, 0, mFbo->getWidth(), mFbo->getHeight())); + const auto& vp = getViewport(); + + GL_CHECK(glScissor(vp.x, vp.y, vp.w, vp.h)); + // clear this fbo if (mClearBuffer) { GL_CHECK(glClearColor(0, 0, 0, 0)); GL_CHECK(glClearStencil(0)); - GL_CHECK(glClearDepthf(1.0)); + GL_CHECK(glClearDepthf(0.0)); GL_CHECK(glDepthMask(1)); GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); @@ -193,7 +209,14 @@ void GlComposeTask::onResolve() { GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, getSelfFbo())); GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getResolveFboId())); - GL_CHECK(glBlitFramebuffer(0, 0, mFbo->getWidth(), mFbo->getHeight(), 0, 0, mFbo->getWidth(), mFbo->getHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST)); + const auto& vp = getViewport(); + + auto x1 = vp.x; + auto y1 = vp.y; + auto x2 = x1 + vp.w; + auto y2 = y1 + vp.h; + + GL_CHECK(glBlitFramebuffer(x1, y1, x2, y2, x1, y1, x2, y2, GL_COLOR_BUFFER_BIT, GL_NEAREST)); } GlBlitTask::GlBlitTask(GlProgram* program, GLuint target, GlRenderTarget* fbo, Array&& tasks) @@ -241,7 +264,6 @@ GlClipTask::GlClipTask(GlRenderTask* clip, GlRenderTask* mask) void GlClipTask::run() { GL_CHECK(glEnable(GL_STENCIL_TEST)); - GL_CHECK(glDepthFunc(GL_ALWAYS)); GL_CHECK(glColorMask(0, 0, 0, 0)); // draw clip path as normal stencil mask GL_CHECK(glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0x1, 0xFF)); @@ -262,15 +284,11 @@ void GlClipTask::run() GL_CHECK(glColorMask(1, 1, 1, 1)); GL_CHECK(glDepthMask(0)); - GL_CHECK(glDepthFunc(GL_LESS)); GL_CHECK(glDisable(GL_STENCIL_TEST)); } -void GlClipClearTask::run() +void GlClipTask::normalizeDrawDepth(int32_t maxDepth) { - GL_CHECK(glDisable(GL_SCISSOR_TEST)); - GL_CHECK(glDepthMask(1)); - GL_CHECK(glClear(GL_DEPTH_BUFFER_BIT)); - GL_CHECK(glDepthMask(0)); - GL_CHECK(glEnable(GL_SCISSOR_TEST)); + mClipTask->normalizeDrawDepth(maxDepth); + mMaskTask->normalizeDrawDepth(maxDepth); } diff --git a/src/renderer/gl_engine/tvgGlRenderTask.h b/src/renderer/gl_engine/tvgGlRenderTask.h index 94fb7157..211808d7 100644 --- a/src/renderer/gl_engine/tvgGlRenderTask.h +++ b/src/renderer/gl_engine/tvgGlRenderTask.h @@ -86,8 +86,11 @@ public: void addBindResource(const GlBindingResource& binding); void setDrawRange(uint32_t offset, uint32_t count); void setViewport(const RenderRegion& viewport); + void setDrawDepth(int32_t depth) { mDrawDepth = static_cast(depth); } + virtual void normalizeDrawDepth(int32_t maxDepth) { mDrawDepth /= static_cast(maxDepth); } GlProgram* getProgram() { return mProgram; } + const RenderRegion& getViewport() const { return mViewport; } private: GlProgram* mProgram; RenderRegion mViewport = {}; @@ -95,6 +98,7 @@ private: uint32_t mIndexCount = {}; Array mVertexLayout = {}; Array mBindingResources = {}; + float mDrawDepth = 0.f; }; class GlStencilCoverTask : public GlRenderTask @@ -105,6 +109,7 @@ public: void run() override; + void normalizeDrawDepth(int32_t maxDepth) override; private: GlRenderTask* mStencilTask; GlRenderTask* mCoverTask; @@ -170,19 +175,10 @@ public: void run() override; + void normalizeDrawDepth(int32_t maxDepth) override; private: GlRenderTask* mClipTask; GlRenderTask* mMaskTask; }; -class GlClipClearTask : public GlRenderTask -{ -public: - GlClipClearTask(): GlRenderTask(nullptr) {} - ~GlClipClearTask() override = default; - - void run() override; -}; - - #endif /* _TVG_GL_RENDER_TASK_H_ */ diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index ca944b57..b2df83f2 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -102,7 +102,7 @@ bool GlRenderer::sync() GL_CHECK(glCullFace(GL_FRONT_AND_BACK)); GL_CHECK(glFrontFace(GL_CCW)); GL_CHECK(glEnable(GL_DEPTH_TEST)); - GL_CHECK(glDepthFunc(GL_LESS)); + GL_CHECK(glDepthFunc(GL_GREATER)); auto task = mRenderPassStack.front().endRenderPass(mPrograms[RT_Blit].get(), mTargetFboId); @@ -227,9 +227,12 @@ bool GlRenderer::renderImage(void* data) if ((sdata->updateFlag & RenderUpdateFlag::Image) == 0) return false; + int32_t drawDepth = currentPass()->nextDrawDepth(); + if (!sdata->clips.empty()) drawClip(sdata->clips); auto task = new GlRenderTask(mPrograms[RT_Image].get()); + task->setDrawDepth(drawDepth); if (!sdata->geometry->draw(task, mGpuBuffer.get(), RenderUpdateFlag::Image)) return false; @@ -267,8 +270,6 @@ bool GlRenderer::renderImage(void* data) currentPass()->addRenderTask(task); - if (!sdata->clips.empty()) currentPass()->addRenderTask(new GlClipClearTask); - return true; } @@ -280,15 +281,32 @@ bool GlRenderer::renderShape(RenderData data) if (sdata->updateFlag == RenderUpdateFlag::None) return false; - if (!sdata->clips.empty()) drawClip(sdata->clips); - uint8_t r = 0, g = 0, b = 0, a = 0; + int32_t drawDepth1 = 0, drawDepth2 = 0, drawDepth3 = 0; + size_t flags = static_cast(sdata->updateFlag); + if (flags == 0) return false; + + if ((flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) && sdata->rshape->fill) drawDepth1 = currentPass()->nextDrawDepth(); + if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform)) + { + sdata->rshape->fillColor(&r, &g, &b, &a); + if (a > 0) drawDepth2 = currentPass()->nextDrawDepth(); + } + + if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::GradientStroke | RenderUpdateFlag::Transform)) + { + sdata->rshape->strokeFill(&r, &g, &b, &a); + if (sdata->rshape->strokeFill() || a > 0) drawDepth3 = currentPass()->nextDrawDepth(); + } + + if (!sdata->clips.empty()) drawClip(sdata->clips); + if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { auto gradient = sdata->rshape->fill; - if (gradient) drawPrimitive(*sdata, gradient, RenderUpdateFlag::Gradient); + if (gradient) drawPrimitive(*sdata, gradient, RenderUpdateFlag::Gradient, drawDepth1); } if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform)) @@ -296,7 +314,7 @@ bool GlRenderer::renderShape(RenderData data) sdata->rshape->fillColor(&r, &g, &b, &a); if (a > 0) { - drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Color); + drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Color, drawDepth2); } } @@ -304,17 +322,15 @@ bool GlRenderer::renderShape(RenderData data) { auto gradient = sdata->rshape->strokeFill(); if (gradient) { - drawPrimitive(*sdata, gradient, RenderUpdateFlag::GradientStroke); + drawPrimitive(*sdata, gradient, RenderUpdateFlag::GradientStroke, drawDepth3); } else { if (sdata->rshape->strokeFill(&r, &g, &b, &a) && a > 0) { - drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Stroke); + drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Stroke, drawDepth3); } } } - if (!sdata->clips.empty()) currentPass()->addRenderTask(new GlClipClearTask); - return true; } @@ -544,16 +560,20 @@ void GlRenderer::initShaders() } -void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag) +void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag, int32_t depth) { auto task = new GlRenderTask(mPrograms[RT_Color].get()); + task->setDrawDepth(depth); if (!sdata.geometry->draw(task, mGpuBuffer.get(), flag)) return; GlRenderTask* stencilTask = nullptr; GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag); - if (stencilMode != GlStencilMode::None) stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task); + if (stencilMode != GlStencilMode::None) { + stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task); + stencilTask->setDrawDepth(depth); + } a = MULTIPLY(a, sdata.opacity); @@ -605,7 +625,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, } -void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag) +void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag, int32_t depth) { const Fill::ColorStop* stops = nullptr; auto stopCnt = min(fill->colorStops(&stops), @@ -622,11 +642,16 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla return; } + task->setDrawDepth(depth); + if (!sdata.geometry->draw(task, mGpuBuffer.get(), flag)) return; GlRenderTask* stencilTask = nullptr; GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag); - if (stencilMode != GlStencilMode::None) stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task); + if (stencilMode != GlStencilMode::None) { + stencilTask = new GlRenderTask(mPrograms[RT_Stencil].get(), task); + stencilTask->setDrawDepth(depth); + } // matrix buffer { @@ -804,11 +829,20 @@ void GlRenderer::drawClip(Array& clips) auto identityIndexOffset = mGpuBuffer->push(indentityIndex.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(); + } + 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 matrix = sdata->geometry->getTransforMatrix(); @@ -827,6 +861,8 @@ void GlRenderer::drawClip(Array& clips) 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, @@ -961,7 +997,13 @@ void GlRenderer::endRenderPass(Compositor* cmp) } auto prev_task = mask_pass.endRenderPass(nullptr, currentPass()->getFboId()); - + prev_task->setDrawDepth(currentPass()->nextDrawDepth()); + prev_task->setViewport(RenderRegion{ + gl_cmp->bbox.x, + static_cast((surface.h - gl_cmp->bbox.y - gl_cmp->bbox.h)), + gl_cmp->bbox.w, + gl_cmp->bbox.h, + }); currentPass()->addRenderTask(prev_task); auto compose_task = self_pass.endRenderPass(program, currentPass()->getFboId()); @@ -978,7 +1020,7 @@ void GlRenderer::endRenderPass(Compositor* cmp) compose_task->addBindResource(GlBindingResource{1, mask_pass.getTextureId(), loc}); } - + compose_task->setDrawDepth(currentPass()->nextDrawDepth()); currentPass()->addRenderTask(compose_task); } else { @@ -989,6 +1031,7 @@ void GlRenderer::endRenderPass(Compositor* cmp) mPrograms[RT_Image].get(), currentPass()->getFboId()); prepareCmpTask(task, gl_cmp->bbox); + task->setDrawDepth(currentPass()->nextDrawDepth()); // matrix buffer { diff --git a/src/renderer/gl_engine/tvgGlRenderer.h b/src/renderer/gl_engine/tvgGlRenderer.h index 9c1a578c..763d713b 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.h +++ b/src/renderer/gl_engine/tvgGlRenderer.h @@ -85,8 +85,8 @@ private: ~GlRenderer(); void initShaders(); - void drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag); - void drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag); + void drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag, int32_t depth); + void drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag, int32_t depth); void drawClip(Array& clips); GlRenderPass* currentPass(); diff --git a/src/renderer/gl_engine/tvgGlShaderSrc.cpp b/src/renderer/gl_engine/tvgGlShaderSrc.cpp index d00b8c4e..c95509c3 100644 --- a/src/renderer/gl_engine/tvgGlShaderSrc.cpp +++ b/src/renderer/gl_engine/tvgGlShaderSrc.cpp @@ -26,13 +26,16 @@ #define TVG_COMPOSE_SHADER(shader) #shader const char* COLOR_VERT_SHADER = TVG_COMPOSE_SHADER( + uniform float uDepth; \n layout(location = 0) in vec2 aLocation; \n layout(std140) uniform Matrix { \n mat4 transform; \n } uMatrix; \n void main() \n { \n - gl_Position = uMatrix.transform * vec4(aLocation, 0.0, 1.0);\n + vec4 pos = uMatrix.transform * vec4(aLocation, 0.0, 1.0); \n + pos.z = uDepth; \n + gl_Position = pos; \n }); const char* COLOR_FRAG_SHADER = TVG_COMPOSE_SHADER( @@ -47,6 +50,7 @@ const char* COLOR_FRAG_SHADER = TVG_COMPOSE_SHADER( }); const char* GRADIENT_VERT_SHADER = TVG_COMPOSE_SHADER( +uniform float uDepth; \n layout(location = 0) in vec2 aLocation; \n out vec2 vPos; \n layout(std140) uniform Matrix { \n @@ -58,7 +62,9 @@ layout(std140) uniform InvMatrix { \n void main() \n { \n - gl_Position = uMatrix.transform * vec4(aLocation, 0.0, 1.0); \n + vec4 glPos = uMatrix.transform * vec4(aLocation, 0.0, 1.0); \n + glPos.z = uDepth; \n + gl_Position = glPos; \n vec4 pos = uInvMatrix.transform * vec4(aLocation, 0.0, 1.0); \n vPos = pos.xy / pos.w; \n }); @@ -224,6 +230,7 @@ const char* RADIAL_GRADIENT_FRAG_SHADER = STR_RADIAL_GRADIENT_FRAG_SHADER.c_str( const char* IMAGE_VERT_SHADER = TVG_COMPOSE_SHADER( + uniform float uDepth; \n layout (location = 0) in vec2 aLocation; \n layout (location = 1) in vec2 aUV; \n layout (std140) uniform Matrix { \n @@ -234,7 +241,9 @@ const char* IMAGE_VERT_SHADER = TVG_COMPOSE_SHADER( \n void main() { \n vUV = aUV; \n - gl_Position = uMatrix.transform * vec4(aLocation, 0.0, 1.0); \n + vec4 pos = uMatrix.transform * vec4(aLocation, 0.0, 1.0); \n + pos.z = uDepth; \n + gl_Position = pos; \n } \n ); @@ -276,6 +285,7 @@ const char* IMAGE_FRAG_SHADER = TVG_COMPOSE_SHADER( ); const char* MASK_VERT_SHADER = TVG_COMPOSE_SHADER( +uniform float uDepth; \n layout(location = 0) in vec2 aLocation; \n layout(location = 1) in vec2 aUV; \n \n @@ -284,7 +294,7 @@ out vec2 vUV; \n void main() { \n vUV = aUV; \n \n - gl_Position = vec4(aLocation, 0.0, 1.0); \n + gl_Position = vec4(aLocation, uDepth, 1.0); \n } \n ); @@ -442,14 +452,16 @@ void main() { \n ); const char* STENCIL_VERT_SHADER = TVG_COMPOSE_SHADER( + uniform float uDepth; \n layout(location = 0) in vec2 aLocation; \n layout(std140) uniform Matrix { \n mat4 transform; \n } uMatrix; \n void main() \n { \n - gl_Position = \n - uMatrix.transform * vec4(aLocation, 0.0, 1.0); \n + vec4 pos = uMatrix.transform * vec4(aLocation, 0.0, 1.0); \n + pos.z = uDepth; \n + gl_Position = pos; \n }); const char* STENCIL_FRAG_SHADER = TVG_COMPOSE_SHADER( diff --git a/src/renderer/gl_engine/tvgGlTessellator.cpp b/src/renderer/gl_engine/tvgGlTessellator.cpp index cef3a8f1..6cca0402 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.cpp +++ b/src/renderer/gl_engine/tvgGlTessellator.cpp @@ -1668,10 +1668,10 @@ void Stroker::stroke(const RenderShape *rshape) RenderRegion Stroker::bounds() const { return RenderRegion { - static_cast(mLeftTop.x), - static_cast(mLeftTop.y), - static_cast(mRightBottom.x - mLeftTop.x), - static_cast(mRightBottom.y - mLeftTop.y), + static_cast(floor(mLeftTop.x)), + static_cast(floor(mLeftTop.y)), + static_cast(ceil(mRightBottom.x - floor(mLeftTop.x))), + static_cast(ceil(mRightBottom.y - floor(mLeftTop.y))), }; } @@ -1802,12 +1802,12 @@ void Stroker::strokeLineTo(const GlPoint &curr) if (ia == 0) { mRightBottom.x = mLeftTop.x = curr.x; mRightBottom.y = mLeftTop.y = curr.y; - } else { - mLeftTop.x = min(mLeftTop.x, curr.x); - mLeftTop.y = min(mLeftTop.y, curr.y); - mRightBottom.x = max(mRightBottom.x, curr.x); - mRightBottom.y = max(mRightBottom.y , curr.y); } + + mLeftTop.x = std::min(mLeftTop.x, min(min(a.x, b.x), min(c.x, d.x))); + mLeftTop.y = std::min(mLeftTop.y, min(min(a.y, b.y), min(c.y, d.y))); + mRightBottom.x = std::max(mRightBottom.x, max(max(a.x, b.x), max(c.x, d.x))); + mRightBottom.y = std::max(mRightBottom.y, max(max(a.y, b.y), max(c.y, d.y))); } void Stroker::strokeCubicTo(const GlPoint &cnt1, const GlPoint &cnt2, const GlPoint &end) @@ -1903,6 +1903,11 @@ void Stroker::strokeRound(const GlPoint &prev, const GlPoint &curr, const GlPoin return; } + mLeftTop.x = std::min(mLeftTop.x, min(center.x, min(prev.x, curr.x))); + mLeftTop.y = std::min(mLeftTop.y, min(center.y, min(prev.y, curr.y))); + mRightBottom.x = std::max(mRightBottom.x, max(center.x, max(prev.x, curr.x))); + mRightBottom.y = std::max(mRightBottom.y, max(center.y, max(prev.y, curr.y))); + // Fixme: just use bezier curve to calculate step count auto count = detail::_bezierCurveCount(detail::_bezFromArc(prev, curr, strokeRadius())); @@ -1930,6 +1935,11 @@ void Stroker::strokeRound(const GlPoint &prev, const GlPoint &curr, const GlPoin this->mResIndices->push(oi); pi = oi; + + mLeftTop.x = std::min(mLeftTop.x, out.x); + mLeftTop.y = std::min(mLeftTop.y, out.y); + mRightBottom.x = std::max(mRightBottom.x, out.x); + mRightBottom.y = std::max(mRightBottom.y, out.y); } } @@ -1965,6 +1975,12 @@ void Stroker::strokeMiter(const GlPoint &prev, const GlPoint &curr, const GlPoin this->mResIndices->push(e); this->mResIndices->push(cp2); this->mResIndices->push(c); + + mLeftTop.x = std::min(mLeftTop.x, join.x); + mLeftTop.y = std::min(mLeftTop.y, join.y); + + mRightBottom.x = std::max(mRightBottom.x, join.x); + mRightBottom.y = std::max(mRightBottom.y, join.y); } void Stroker::strokeBevel(const GlPoint &prev, const GlPoint &curr, const GlPoint ¢er) @@ -2000,6 +2016,11 @@ void Stroker::strokeSquare(const GlPoint& p, const GlPoint& outDir) mResIndices->push(ci); mResIndices->push(bi); mResIndices->push(di); + + mLeftTop.x = std::min(mLeftTop.x, min(min(a.x, b.x), min(c.x, d.x))); + mLeftTop.y = std::min(mLeftTop.y, min(min(a.y, b.y), min(c.y, d.y))); + mRightBottom.x = std::max(mRightBottom.x, max(max(a.x, b.x), max(c.x, d.x))); + mRightBottom.y = std::max(mRightBottom.y, max(max(a.y, b.y), max(c.y, d.y))); } void Stroker::strokeRound(const GlPoint& p, const GlPoint& outDir) @@ -2262,10 +2283,10 @@ void BWTessellator::tessellate(const RenderShape *rshape, const Matrix& matrix) RenderRegion BWTessellator::bounds() const { return RenderRegion { - static_cast(mLeftTop.x), - static_cast(mLeftTop.y), - static_cast(mRightBottom.x - mLeftTop.x), - static_cast(mRightBottom.y - mLeftTop.y), + static_cast(floor(mLeftTop.x)), + static_cast(floor(mLeftTop.y)), + static_cast(ceil(mRightBottom.x - floor(mLeftTop.x))), + static_cast(ceil(mRightBottom.y - floor(mLeftTop.y))), }; }