gl_engine: optimize off-screen rendering

Performing a full-screen RenderPass resolve is too expensive.
Because most composite cases only require a small area to be rendered off-screen.
To improve performance, use the bounds of the Geometry for off-screen rendering whenever possible
This commit is contained in:
RuiwenTang 2024-06-25 22:15:30 +08:00 committed by Hermet Park
parent 53a570e680
commit 76f98008e8
11 changed files with 479 additions and 173 deletions

View file

@ -6,6 +6,7 @@ source_file = [
'tvgGlProgram.h', 'tvgGlProgram.h',
'tvgGlRenderer.h', 'tvgGlRenderer.h',
'tvgGlRenderPass.h', 'tvgGlRenderPass.h',
'tvgGlRenderTarget.h',
'tvgGlRenderTask.h', 'tvgGlRenderTask.h',
'tvgGlShader.h', 'tvgGlShader.h',
'tvgGlShaderSrc.h', 'tvgGlShaderSrc.h',
@ -14,6 +15,7 @@ source_file = [
'tvgGlProgram.cpp', 'tvgGlProgram.cpp',
'tvgGlRenderer.cpp', 'tvgGlRenderer.cpp',
'tvgGlRenderPass.cpp', 'tvgGlRenderPass.cpp',
'tvgGlRenderTarget.cpp',
'tvgGlRenderTask.cpp', 'tvgGlRenderTask.cpp',
'tvgGlShader.cpp', 'tvgGlShader.cpp',
'tvgGlShaderSrc.cpp', 'tvgGlShaderSrc.cpp',

View file

@ -211,29 +211,17 @@ bool GlGeometry::draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdate
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), vertexOffset}); task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), vertexOffset});
} }
task->setDrawRange(indexOffset, indexBuffer->count); task->setDrawRange(indexOffset, indexBuffer->count);
task->setViewport(viewport);
return true; return true;
} }
void GlGeometry::updateTransform(const RenderTransform* transform, float w, float h) void GlGeometry::updateTransform(const RenderTransform* transform)
{ {
float modelMatrix[16];
if (transform) { if (transform) {
GET_MATRIX44(transform->m, modelMatrix);
mMatrix = transform->m; mMatrix = transform->m;
} else { } else {
memset(modelMatrix, 0, 16 * sizeof(float));
modelMatrix[0] = 1.f;
modelMatrix[5] = 1.f;
modelMatrix[10] = 1.f;
modelMatrix[15] = 1.f;
mMatrix = Matrix{1, 0, 0, 0, 1, 0, 0, 0, 1}; mMatrix = Matrix{1, 0, 0, 0, 1, 0, 0, 0, 1};
} }
MVP_MATRIX();
MULTIPLY_MATRIX(mvp, modelMatrix, mTransform)
} }
void GlGeometry::setViewport(const RenderRegion& viewport) void GlGeometry::setViewport(const RenderRegion& viewport)
@ -241,9 +229,14 @@ void GlGeometry::setViewport(const RenderRegion& viewport)
this->viewport = viewport; this->viewport = viewport;
} }
float* GlGeometry::getTransformMatrix() const RenderRegion& GlGeometry::getViewport()
{ {
return mTransform; return viewport;
}
const Matrix& GlGeometry::getTransformMatrix()
{
return mMatrix;
} }
GlStencilMode GlGeometry::getStencilMode(RenderUpdateFlag flag) GlStencilMode GlGeometry::getStencilMode(RenderUpdateFlag flag)

View file

@ -28,7 +28,7 @@
#include "tvgMath.h" #include "tvgMath.h"
#define MVP_MATRIX() \ #define MVP_MATRIX(w, h) \
float mvp[4*4] = { \ float mvp[4*4] = { \
2.f / w, 0.0, 0.0f, 0.0f, \ 2.f / w, 0.0, 0.0f, 0.0f, \
0.0, -2.f / h, 0.0f, 0.0f, \ 0.0, -2.f / h, 0.0f, 0.0f, \
@ -192,9 +192,10 @@ public:
bool tesselate(const Surface* image, const RenderMesh* mesh, RenderUpdateFlag flag); bool tesselate(const Surface* image, const RenderMesh* mesh, RenderUpdateFlag flag);
void disableVertex(uint32_t location); void disableVertex(uint32_t location);
bool draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdateFlag flag); bool draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdateFlag flag);
void updateTransform(const RenderTransform* transform, float w, float h); void updateTransform(const RenderTransform* transform);
void setViewport(const RenderRegion& viewport); void setViewport(const RenderRegion& viewport);
float* getTransformMatrix(); const RenderRegion& getViewport();
const Matrix& getTransformMatrix();
GlStencilMode getStencilMode(RenderUpdateFlag flag); GlStencilMode getStencilMode(RenderUpdateFlag flag);
RenderRegion getBounds() const; RenderRegion getBounds() const;
@ -204,7 +205,6 @@ private:
Array<float> strokeVertex = {}; Array<float> strokeVertex = {};
Array<uint32_t> fillIndex = {}; Array<uint32_t> fillIndex = {};
Array<uint32_t> strokeIndex = {}; Array<uint32_t> strokeIndex = {};
float mTransform[16];
Matrix mMatrix = {}; Matrix mMatrix = {};
FillRule mFillRule = FillRule::Winding; FillRule mFillRule = FillRule::Winding;

View file

@ -21,67 +21,10 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "tvgMath.h"
#include "tvgGlRenderPass.h" #include "tvgGlRenderPass.h"
#include "tvgGlRenderTask.h" #include "tvgGlRenderTask.h"
#include "tvgGlGeometry.h"
GlRenderTarget::GlRenderTarget(uint32_t width, uint32_t height): mWidth(width), mHeight(height) {}
GlRenderTarget::~GlRenderTarget()
{
if (mFbo == 0) return;
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
GL_CHECK(glDeleteFramebuffers(1, &mFbo));
if (mColorTex != 0) {
GL_CHECK(glDeleteTextures(1, &mColorTex));
}
if (mDepthStencilBuffer != 0) {
GL_CHECK(glDeleteRenderbuffers(1, &mDepthStencilBuffer));
}
}
void GlRenderTarget::init(GLint resolveId)
{
if (mFbo != 0 || mWidth == 0 || mHeight == 0) return;
GL_CHECK(glGenFramebuffers(1, &mFbo));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mFbo));
GL_CHECK(glGenRenderbuffers(1, &mColorBuffer));
GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, mColorBuffer));
GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, mWidth, mHeight));
GL_CHECK(glGenRenderbuffers(1, &mDepthStencilBuffer));
GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, mDepthStencilBuffer));
GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, mWidth, mHeight));
GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0));
GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mColorBuffer));
GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepthStencilBuffer));
// resolve target
GL_CHECK(glGenTextures(1, &mColorTex));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, mColorTex));
GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
GL_CHECK(glGenFramebuffers(1, &mResolveFbo));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mResolveFbo));
GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mColorTex, 0));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, resolveId));
}
GlRenderPass::GlRenderPass(GlRenderTarget* fbo): mFbo(fbo), mTasks(), mDrawDepth(0) {} GlRenderPass::GlRenderPass(GlRenderTarget* fbo): mFbo(fbo), mTasks(), mDrawDepth(0) {}
@ -109,3 +52,20 @@ void GlRenderPass::addRenderTask(GlRenderTask* task)
{ {
mTasks.push(task); mTasks.push(task);
} }
void GlRenderPass::getMatrix(float *dst, const Matrix &matrix) const
{
const auto& vp = getViewport();
Matrix postMatrix{};
mathIdentity(&postMatrix);
mathTranslate(&postMatrix, -vp.x, -vp.y);
auto m = postMatrix * matrix;
float modelMatrix[16];
GET_MATRIX44(m, modelMatrix);
MVP_MATRIX(vp.w, vp.h);
MULTIPLY_MATRIX(mvp, modelMatrix, dst);
}

View file

@ -28,34 +28,10 @@
#include "tvgGlCommon.h" #include "tvgGlCommon.h"
#include "tvgGlRenderTask.h" #include "tvgGlRenderTask.h"
#include "tvgGlRenderTarget.h"
class GlProgram; class GlProgram;
class GlRenderTarget
{
public:
GlRenderTarget(uint32_t width, uint32_t height);
~GlRenderTarget();
void init(GLint resolveId);
GLuint getFboId() { return mFbo; }
GLuint getResolveFboId() { return mResolveFbo; }
GLuint getColorTexture() { return mColorTex; }
uint32_t getWidth() const { return mWidth; }
uint32_t getHeight() const { return mHeight; }
private:
uint32_t mWidth = 0;
uint32_t mHeight = 0;
GLuint mFbo = 0;
GLuint mColorBuffer = 0;
GLuint mDepthStencilBuffer = 0;
GLuint mResolveFbo = 0;
GLuint mColorTex = 0;
};
class GlRenderPass class GlRenderPass
{ {
public: public:
@ -64,12 +40,22 @@ public:
~GlRenderPass(); ~GlRenderPass();
bool isEmpty() const { return mFbo == nullptr; }
void addRenderTask(GlRenderTask* task); void addRenderTask(GlRenderTask* task);
GLuint getFboId() { return mFbo->getFboId(); } GLuint getFboId() { return mFbo->getFboId(); }
GLuint getTextureId() { return mFbo->getColorTexture(); } GLuint getTextureId() { return mFbo->getColorTexture(); }
const RenderRegion& getViewport() const { return mFbo->getViewport(); }
uint32_t getFboWidth() const { return mFbo->getWidth(); }
uint32_t getFboHeight() const { return mFbo->getHeight(); }
void getMatrix(float dst[16], const Matrix& matrix) const;
template <class T> template <class T>
T* endRenderPass(GlProgram* program, GLuint targetFbo) { T* endRenderPass(GlProgram* program, GLuint targetFbo) {
int32_t maxDepth = mDrawDepth + 1; int32_t maxDepth = mDrawDepth + 1;
@ -78,7 +64,13 @@ public:
mTasks[i]->normalizeDrawDepth(maxDepth); mTasks[i]->normalizeDrawDepth(maxDepth);
} }
return new T(program, targetFbo, mFbo, std::move(mTasks)); auto task = new T(program, targetFbo, mFbo, std::move(mTasks));
const auto& vp = mFbo->getViewport();
task->setRenderSize(static_cast<uint32_t>(vp.w), static_cast<uint32_t>(vp.h));
return task;
} }
int nextDrawDepth() { return ++mDrawDepth; } int nextDrawDepth() { return ++mDrawDepth; }

View file

@ -0,0 +1,132 @@
/*
* Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "tvgGlRenderTarget.h"
GlRenderTarget::GlRenderTarget(uint32_t width, uint32_t height): mWidth(width), mHeight(height) {}
GlRenderTarget::~GlRenderTarget()
{
if (mFbo == 0) return;
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
GL_CHECK(glDeleteFramebuffers(1, &mFbo));
if (mColorTex != 0) {
GL_CHECK(glDeleteTextures(1, &mColorTex));
}
if (mDepthStencilBuffer != 0) {
GL_CHECK(glDeleteRenderbuffers(1, &mDepthStencilBuffer));
}
}
void GlRenderTarget::init(GLint resolveId)
{
if (mFbo != 0 || mWidth == 0 || mHeight == 0) return;
GL_CHECK(glGenFramebuffers(1, &mFbo));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mFbo));
GL_CHECK(glGenRenderbuffers(1, &mColorBuffer));
GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, mColorBuffer));
GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, mWidth, mHeight));
GL_CHECK(glGenRenderbuffers(1, &mDepthStencilBuffer));
GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, mDepthStencilBuffer));
GL_CHECK(glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, mWidth, mHeight));
GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0));
GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mColorBuffer));
GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepthStencilBuffer));
// resolve target
GL_CHECK(glGenTextures(1, &mColorTex));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, mColorTex));
GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
GL_CHECK(glGenFramebuffers(1, &mResolveFbo));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mResolveFbo));
GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mColorTex, 0));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, resolveId));
}
GlRenderTargetPool::GlRenderTargetPool(uint32_t maxWidth, uint32_t maxHeight): mMaxWidth(maxWidth), mMaxHeight(maxHeight), mPool() {}
GlRenderTargetPool::~GlRenderTargetPool()
{
for (uint32_t i = 0; i < mPool.count; i++) {
delete mPool[i];
}
}
uint32_t alignPow2(uint32_t value)
{
uint32_t ret = 1;
while (ret < value) {
ret <<= 1;
}
return ret;
}
GlRenderTarget* GlRenderTargetPool::getRenderTarget(const RenderRegion& vp, GLuint resolveId)
{
uint32_t width = static_cast<uint32_t>(vp.w);
uint32_t height = static_cast<uint32_t>(vp.h);
// pow2 align width and height
if (width >= mMaxWidth) width = mMaxWidth;
else width = alignPow2(width);
if (width >= mMaxWidth) width = mMaxWidth;
if (height >= mMaxHeight) height = mMaxHeight;
else height = alignPow2(height);
if (height >= mMaxHeight) height = mMaxHeight;
for (uint32_t i = 0; i < mPool.count; i++) {
auto rt = mPool[i];
if (rt->getWidth() == width && rt->getHeight() == height) {
rt->setViewport(vp);
return rt;
}
}
auto rt = new GlRenderTarget(width, height);
rt->init(resolveId);
rt->setViewport(vp);
mPool.push(rt);
return rt;
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _TVG_GL_RENDER_RENDER_TARGET_H_
#define _TVG_GL_RENDER_RENDER_TARGET_H_
#include "tvgGlCommon.h"
class GlRenderTarget
{
public:
GlRenderTarget(uint32_t width, uint32_t height);
~GlRenderTarget();
void init(GLint resolveId);
GLuint getFboId() { return mFbo; }
GLuint getResolveFboId() { return mResolveFbo; }
GLuint getColorTexture() { return mColorTex; }
uint32_t getWidth() const { return mWidth; }
uint32_t getHeight() const { return mHeight; }
void setViewport(const RenderRegion& vp) { mViewport = vp; }
const RenderRegion& getViewport() const { return mViewport; }
private:
uint32_t mWidth = 0;
uint32_t mHeight = 0;
RenderRegion mViewport{};
GLuint mFbo = 0;
GLuint mColorBuffer = 0;
GLuint mDepthStencilBuffer = 0;
GLuint mResolveFbo = 0;
GLuint mColorTex = 0;
};
class GlRenderTargetPool {
public:
GlRenderTargetPool(uint32_t maxWidth, uint32_t maxHeight);
~GlRenderTargetPool();
GlRenderTarget* getRenderTarget(const RenderRegion& vp, GLuint resolveId = 0);
private:
uint32_t mMaxWidth = 0;
uint32_t mMaxHeight = 0;
Array<GlRenderTarget*> mPool;
};
#endif //_TVG_GL_RENDER_RENDER_TARGET_H_

View file

@ -103,6 +103,13 @@ void GlRenderTask::setDrawRange(uint32_t offset, uint32_t count)
void GlRenderTask::setViewport(const RenderRegion &viewport) void GlRenderTask::setViewport(const RenderRegion &viewport)
{ {
mViewport = viewport; mViewport = viewport;
if (mViewport.w < 0) {
mViewport.w = 0;
}
if (mViewport.h < 0) {
mViewport.h = 0;
}
} }
GlStencilCoverTask::GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover, GlStencilMode mode) GlStencilCoverTask::GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover, GlStencilMode mode)
@ -172,11 +179,9 @@ GlComposeTask::~GlComposeTask()
void GlComposeTask::run() void GlComposeTask::run()
{ {
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getSelfFbo())); GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getSelfFbo()));
GL_CHECK(glViewport(0, 0, mFbo->getWidth(), mFbo->getHeight())); GL_CHECK(glViewport(0, 0, mRenderWidth, mRenderHeight));
const auto& vp = getViewport(); GL_CHECK(glScissor(0, 0, mRenderWidth, mRenderHeight));
GL_CHECK(glScissor(vp.x, vp.y, vp.w, vp.h));
// clear this fbo // clear this fbo
if (mClearBuffer) { if (mClearBuffer) {
@ -211,14 +216,8 @@ void GlComposeTask::onResolve() {
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, getSelfFbo())); GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, getSelfFbo()));
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getResolveFboId())); GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getResolveFboId()));
const auto& vp = getViewport();
auto x1 = vp.x; GL_CHECK(glBlitFramebuffer(0, 0, mRenderWidth, mRenderHeight, 0, 0, mRenderWidth, mRenderHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST));
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<GlRenderTask*>&& tasks) GlBlitTask::GlBlitTask(GlProgram* program, GLuint target, GlRenderTarget* fbo, Array<GlRenderTask*>&& tasks)
@ -251,12 +250,21 @@ GlDrawBlitTask::GlDrawBlitTask(GlProgram* program, GLuint target, GlRenderTarget
{ {
} }
GlDrawBlitTask::~GlDrawBlitTask()
{
if (mPrevTask) delete mPrevTask;
}
void GlDrawBlitTask::run() void GlDrawBlitTask::run()
{ {
if (mPrevTask) mPrevTask->run();
GlComposeTask::run(); GlComposeTask::run();
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo())); GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()));
GL_CHECK(glViewport(0, 0, mParentWidth, mParentHeight));
GL_CHECK(glScissor(0, 0, mParentWidth, mParentWidth));
GlRenderTask::run(); GlRenderTask::run();
} }

View file

@ -126,6 +126,8 @@ public:
void run() override; void run() override;
void setRenderSize(uint32_t width, uint32_t height) { mRenderWidth = width; mRenderHeight = height; }
bool mClearBuffer = true; bool mClearBuffer = true;
protected: protected:
@ -140,6 +142,8 @@ private:
GLuint mTargetFbo; GLuint mTargetFbo;
GlRenderTarget* mFbo; GlRenderTarget* mFbo;
Array<GlRenderTask*> mTasks; Array<GlRenderTask*> mTasks;
uint32_t mRenderWidth = 0;
uint32_t mRenderHeight = 0;
}; };
class GlBlitTask : public GlComposeTask class GlBlitTask : public GlComposeTask
@ -162,9 +166,18 @@ class GlDrawBlitTask : public GlComposeTask
{ {
public: public:
GlDrawBlitTask(GlProgram*, GLuint target, GlRenderTarget* fbo, Array<GlRenderTask*>&& tasks); GlDrawBlitTask(GlProgram*, GLuint target, GlRenderTarget* fbo, Array<GlRenderTask*>&& tasks);
~GlDrawBlitTask() override = default; ~GlDrawBlitTask() override;
void setPrevTask(GlRenderTask* task) { mPrevTask = task; }
void setParentSize(uint32_t width, uint32_t height) { mParentWidth = width; mParentHeight = height; }
void run() override; void run() override;
private:
GlRenderTask* mPrevTask = nullptr;
uint32_t mParentWidth = 0;
uint32_t mParentHeight = 0;
}; };
class GlClipTask : public GlRenderTask class GlClipTask : public GlRenderTask

View file

@ -66,6 +66,7 @@ bool GlRenderer::target(int32_t id, uint32_t w, uint32_t h)
mTargetFboId = static_cast<GLint>(id); mTargetFboId = static_cast<GLint>(id);
mRootTarget = make_unique<GlRenderTarget>(surface.w, surface.h); mRootTarget = make_unique<GlRenderTarget>(surface.w, surface.h);
mRootTarget->setViewport(RenderRegion{0, 0, static_cast<int32_t>(surface.w), static_cast<int32_t>(surface.h)});
mRootTarget->init(mTargetFboId); mRootTarget->init(mTargetFboId);
mRenderPassStack.clear(); mRenderPassStack.clear();
@ -119,8 +120,15 @@ bool GlRenderer::sync()
RenderRegion GlRenderer::region(RenderData data) RenderRegion GlRenderer::region(RenderData data)
{ {
if (currentPass()->isEmpty()) return RenderRegion{0, 0, 0, 0};
auto shape = reinterpret_cast<GlShape*>(data); auto shape = reinterpret_cast<GlShape*>(data);
return shape->geometry->getBounds(); auto bounds = shape->geometry->getBounds();
auto const& vp = currentPass()->getViewport();
bounds.intersect(vp);
return bounds;
} }
@ -145,7 +153,12 @@ bool GlRenderer::postRender()
Compositor* GlRenderer::target(const RenderRegion& region, TVG_UNUSED ColorSpace cs) Compositor* GlRenderer::target(const RenderRegion& region, TVG_UNUSED ColorSpace cs)
{ {
mComposeStack.emplace_back(make_unique<GlCompositor>(region)); auto vp = region;
if (currentPass()->isEmpty()) return nullptr;
vp.intersect(currentPass()->getViewport());
mComposeStack.emplace_back(make_unique<GlCompositor>(vp));
return mComposeStack.back().get(); return mComposeStack.back().get();
} }
@ -160,10 +173,18 @@ bool GlRenderer::beginComposite(Compositor* cmp, CompositeMethod method, uint8_t
uint32_t index = mRenderPassStack.size() - 1; uint32_t index = mRenderPassStack.size() - 1;
if (index >= mComposePool.count) { if (index >= mComposePool.count) {
mComposePool.push( new GlRenderTarget(surface.w, surface.h)); mComposePool.push( new GlRenderTargetPool(surface.w, surface.h));
mComposePool[index]->init(mTargetFboId); }
auto glCmp = static_cast<GlCompositor*>(cmp);
if (glCmp->bbox.w > 0 && glCmp->bbox.h > 0) {
auto renderTarget = mComposePool[index]->getRenderTarget(glCmp->bbox);
mRenderPassStack.emplace_back(GlRenderPass(renderTarget));
} else {
// empty render pass
mRenderPassStack.emplace_back(GlRenderPass(nullptr));
} }
mRenderPassStack.emplace_back(GlRenderPass(mComposePool[index]));
return true; return true;
} }
@ -214,7 +235,20 @@ bool GlRenderer::renderImage(void* data)
if (!sdata) return false; if (!sdata) return false;
if (currentPass()->isEmpty()) return true;
if ((sdata->updateFlag & RenderUpdateFlag::Image) == 0) return true; if ((sdata->updateFlag & RenderUpdateFlag::Image) == 0) return true;
const auto& vp = currentPass()->getViewport();
auto bbox = sdata->geometry->getViewport();
bbox.intersect(vp);
if (bbox.w <= 0 || bbox.h <= 0) return true;
auto x = bbox.x - vp.x;
auto y = bbox.y - vp.y;
int32_t drawDepth = currentPass()->nextDrawDepth(); int32_t drawDepth = currentPass()->nextDrawDepth();
@ -227,14 +261,19 @@ bool GlRenderer::renderImage(void* data)
// matrix buffer // matrix buffer
{ {
auto matrix = sdata->geometry->getTransformMatrix(); const auto& matrix = sdata->geometry->getTransformMatrix();
float matrix44[16];
currentPass()->getMatrix(matrix44, matrix);
uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix");
task->addBindResource(GlBindingResource{ task->addBindResource(GlBindingResource{
0, 0,
loc, loc,
mGpuBuffer->getBufferId(), mGpuBuffer->getBufferId(),
mGpuBuffer->push(matrix, 16 * sizeof(float), true), mGpuBuffer->push(matrix44, 16 * sizeof(float), true),
16 * sizeof(float), 16 * sizeof(float),
}); });
} }
@ -257,6 +296,13 @@ bool GlRenderer::renderImage(void* data)
task->addBindResource(GlBindingResource{0, sdata->texId, loc}); task->addBindResource(GlBindingResource{0, sdata->texId, loc});
} }
task->setViewport(RenderRegion{
x,
vp.h - y - bbox.h,
bbox.w,
bbox.h
});
currentPass()->addRenderTask(task); currentPass()->addRenderTask(task);
return true; return true;
@ -268,8 +314,17 @@ bool GlRenderer::renderShape(RenderData data)
auto sdata = static_cast<GlShape*>(data); auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false; if (!sdata) return false;
if (currentPass()->isEmpty()) return true;
if (sdata->updateFlag == RenderUpdateFlag::None) return true; if (sdata->updateFlag == RenderUpdateFlag::None) return true;
const auto& vp = currentPass()->getViewport();
auto bbox = sdata->geometry->getViewport();
bbox.intersect(vp);
if (bbox.w <= 0 || bbox.h <= 0) return true;
uint8_t r = 0, g = 0, b = 0, a = 0; uint8_t r = 0, g = 0, b = 0, a = 0;
int32_t drawDepth1 = 0, drawDepth2 = 0, drawDepth3 = 0; int32_t drawDepth1 = 0, drawDepth2 = 0, drawDepth3 = 0;
@ -355,7 +410,7 @@ static GLuint _genTexture(Surface* image)
RenderData GlRenderer::prepare(Surface* image, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags) RenderData GlRenderer::prepare(Surface* image, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags)
{ {
if (flags == RenderUpdateFlag::None) return nullptr; if (flags == RenderUpdateFlag::None) return data;
auto sdata = static_cast<GlShape*>(data); auto sdata = static_cast<GlShape*>(data);
@ -373,13 +428,8 @@ RenderData GlRenderer::prepare(Surface* image, const RenderMesh* mesh, RenderDat
sdata->geometry = make_unique<GlGeometry>(); sdata->geometry = make_unique<GlGeometry>();
} }
sdata->geometry->updateTransform(transform, sdata->viewWd, sdata->viewHt); sdata->geometry->updateTransform(transform);
sdata->geometry->setViewport(RenderRegion{ sdata->geometry->setViewport(mViewport);
mViewport.x,
static_cast<int32_t>((surface.h - mViewport.y - mViewport.h)),
mViewport.w,
mViewport.h,
});
sdata->geometry->tesselate(image, mesh, flags); sdata->geometry->tesselate(image, mesh, flags);
@ -438,13 +488,8 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const
if (sdata->updateFlag == RenderUpdateFlag::None) return sdata; if (sdata->updateFlag == RenderUpdateFlag::None) return sdata;
sdata->geometry->updateTransform(transform, sdata->viewWd, sdata->viewHt); sdata->geometry->updateTransform(transform);
sdata->geometry->setViewport(RenderRegion{ sdata->geometry->setViewport(mViewport);
mViewport.x,
static_cast<int32_t>(surface.h - mViewport.y - mViewport.h),
mViewport.w,
mViewport.h,
});
if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::GradientStroke | RenderUpdateFlag::Transform | RenderUpdateFlag::Path)) if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::GradientStroke | RenderUpdateFlag::Transform | RenderUpdateFlag::Path))
{ {
@ -563,6 +608,16 @@ void GlRenderer::initShaders()
void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag, int32_t depth) 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()); auto task = new GlRenderTask(mPrograms[RT_Color].get());
task->setDrawDepth(depth); task->setDrawDepth(depth);
@ -571,6 +626,13 @@ void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b,
return; return;
} }
task->setViewport(RenderRegion {
x,
vp.h - y - h,
w,
h
});
GlRenderTask* stencilTask = nullptr; GlRenderTask* stencilTask = nullptr;
GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag); GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag);
@ -583,10 +645,15 @@ void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b,
// matrix buffer // matrix buffer
{ {
auto matrix = sdata.geometry->getTransformMatrix(); const auto& matrix = sdata.geometry->getTransformMatrix();
float matrix44[16];
currentPass()->getMatrix(matrix44, matrix);
uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix");
uint32_t viewOffset = mGpuBuffer->push(matrix, 16 * sizeof(float), true); uint32_t viewOffset = mGpuBuffer->push(matrix44, 16 * sizeof(float), true);
task->addBindResource(GlBindingResource{ task->addBindResource(GlBindingResource{
0, 0,
@ -631,6 +698,12 @@ void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b,
void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag, int32_t depth) 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; const Fill::ColorStop* stops = nullptr;
auto stopCnt = min(fill->colorStops(&stops), auto stopCnt = min(fill->colorStops(&stops),
static_cast<uint32_t>(MAX_GRADIENT_STOPS)); static_cast<uint32_t>(MAX_GRADIENT_STOPS));
@ -648,7 +721,20 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
task->setDrawDepth(depth); task->setDrawDepth(depth);
if (!sdata.geometry->draw(task, mGpuBuffer.get(), flag)) return; 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; GlRenderTask* stencilTask = nullptr;
GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag); GlStencilMode stencilMode = sdata.geometry->getStencilMode(flag);
@ -659,7 +745,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
// matrix buffer // matrix buffer
{ {
auto matrix = sdata.geometry->getTransformMatrix(); const auto& matrix = sdata.geometry->getTransformMatrix();
auto gradientTransform = fill->transform(); auto gradientTransform = fill->transform();
float invMat4[16]; float invMat4[16];
@ -676,9 +762,13 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
invMat4[15] = 1.f; invMat4[15] = 1.f;
} }
float matrix44[16];
currentPass()->getMatrix(matrix44, matrix);
uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix"); uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix");
uint32_t viewOffset = mGpuBuffer->push(matrix, 16 * sizeof(float), true); uint32_t viewOffset = mGpuBuffer->push(matrix44, 16 * sizeof(float), true);
task->addBindResource(GlBindingResource{ task->addBindResource(GlBindingResource{
0, 0,
@ -840,6 +930,8 @@ void GlRenderer::drawClip(Array<RenderData>& clips)
clipDepths[i] = currentPass()->nextDrawDepth(); clipDepths[i] = currentPass()->nextDrawDepth();
} }
const auto& vp = currentPass()->getViewport();
for (uint32_t i = 0; i < clips.count; ++i) { for (uint32_t i = 0; i < clips.count; ++i) {
auto sdata = static_cast<GlShape*>(clips[i]); auto sdata = static_cast<GlShape*>(clips[i]);
@ -849,11 +941,29 @@ void GlRenderer::drawClip(Array<RenderData>& clips)
sdata->geometry->draw(clipTask, mGpuBuffer.get(), RenderUpdateFlag::Path); sdata->geometry->draw(clipTask, mGpuBuffer.get(), RenderUpdateFlag::Path);
auto matrix = sdata->geometry->getTransformMatrix(); 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 loc = clipTask->getProgram()->getUniformBlockIndex("Matrix");
uint32_t viewOffset = mGpuBuffer->push(matrix, 16 * sizeof(float), true); uint32_t viewOffset = mGpuBuffer->push(matrix44, 16 * sizeof(float), true);
clipTask->addBindResource(GlBindingResource{ clipTask->addBindResource(GlBindingResource{
0, 0,
@ -876,7 +986,7 @@ void GlRenderer::drawClip(Array<RenderData>& clips)
}); });
maskTask->setDrawRange(identityIndexOffset, 6); maskTask->setDrawRange(identityIndexOffset, 6);
maskTask->setViewport(RenderRegion{0, 0, static_cast<int32_t>(surface.w), static_cast<int32_t>(surface.h)}); maskTask->setViewport(RenderRegion{0, 0, static_cast<int32_t>(vp.w), static_cast<int32_t>(vp.h)});
currentPass()->addRenderTask(new GlClipTask(clipTask, maskTask)); currentPass()->addRenderTask(new GlClipTask(clipTask, maskTask));
} }
@ -891,7 +1001,8 @@ GlRenderPass* GlRenderer::currentPass()
void GlRenderer::prepareBlitTask(GlBlitTask* task) void GlRenderer::prepareBlitTask(GlBlitTask* task)
{ {
prepareCmpTask(task, mViewport); RenderRegion region{0, 0, static_cast<int32_t>(surface.w), static_cast<int32_t>(surface.h)};
prepareCmpTask(task, region, surface.w, surface.h);
{ {
uint32_t loc = task->getProgram()->getUniformLocation("uSrcTexture"); uint32_t loc = task->getProgram()->getUniformLocation("uSrcTexture");
@ -899,21 +1010,43 @@ void GlRenderer::prepareBlitTask(GlBlitTask* task)
} }
} }
void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp) 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 // we use 1:1 blit mapping since compositor fbo is same size as root fbo
Array<float> vertices(4 * 4); Array<float> vertices(4 * 4);
float left = -1.f; const auto& passVp = currentPass()->getViewport();
float top = 1.f;
float right = 1.f; auto taskVp = vp;
float bottom = -1.f; 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<float>(passVp.w);
float rh = static_cast<float>(passVp.h);
float l = static_cast<float>(x);
float t = static_cast<float>(rh - y);
float r = static_cast<float>(x + w);
float b = static_cast<float>(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<float>(w) / static_cast<float>(cmpWidth);
float uh = static_cast<float>(h) / static_cast<float>(cmpHeight);
// left top point // left top point
vertices.push(left); vertices.push(left);
vertices.push(top); vertices.push(top);
vertices.push(0.f); vertices.push(0.f);
vertices.push(1.f); vertices.push(uh);
// left bottom point // left bottom point
vertices.push(left); vertices.push(left);
vertices.push(bottom); vertices.push(bottom);
@ -922,12 +1055,12 @@ void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp)
// right top point // right top point
vertices.push(right); vertices.push(right);
vertices.push(top); vertices.push(top);
vertices.push(1.f); vertices.push(uw);
vertices.push(1.f); vertices.push(uh);
// right bottom point // right bottom point
vertices.push(right); vertices.push(right);
vertices.push(bottom); vertices.push(bottom);
vertices.push(1.f); vertices.push(uw);
vertices.push(0.f); vertices.push(0.f);
Array<uint32_t> indices(6); Array<uint32_t> indices(6);
@ -946,11 +1079,12 @@ void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp)
task->addVertexLayout(GlVertexLayout{1, 2, 4 * sizeof(float), vertexOffset + 2 * sizeof(float)}); task->addVertexLayout(GlVertexLayout{1, 2, 4 * sizeof(float), vertexOffset + 2 * sizeof(float)});
task->setDrawRange(indexOffset, indices.count); task->setDrawRange(indexOffset, indices.count);
task->setViewport(RenderRegion{ task->setViewport(RenderRegion{
vp.x, x,
static_cast<int32_t>((surface.h - vp.y - vp.h)), static_cast<int32_t>((passVp.h - y - h)),
vp.w, w,
vp.h, h,
}); });
} }
@ -965,6 +1099,8 @@ void GlRenderer::endRenderPass(Compositor* cmp)
auto mask_pass = std::move(mRenderPassStack.back()); auto mask_pass = std::move(mRenderPassStack.back());
mRenderPassStack.pop_back(); mRenderPassStack.pop_back();
if (self_pass.isEmpty() || mask_pass.isEmpty()) return;
GlProgram* program = nullptr; GlProgram* program = nullptr;
switch(cmp->method) { switch(cmp->method) {
case CompositeMethod::ClipPath: case CompositeMethod::ClipPath:
@ -1002,17 +1138,14 @@ void GlRenderer::endRenderPass(Compositor* cmp)
auto prev_task = mask_pass.endRenderPass<GlComposeTask>(nullptr, currentPass()->getFboId()); auto prev_task = mask_pass.endRenderPass<GlComposeTask>(nullptr, currentPass()->getFboId());
prev_task->setDrawDepth(currentPass()->nextDrawDepth()); prev_task->setDrawDepth(currentPass()->nextDrawDepth());
prev_task->setViewport(RenderRegion{ prev_task->setRenderSize(static_cast<uint32_t>(gl_cmp->bbox.w), static_cast<uint32_t>(gl_cmp->bbox.h));
gl_cmp->bbox.x, prev_task->setViewport(gl_cmp->bbox);
static_cast<int32_t>((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<GlDrawBlitTask>(program, currentPass()->getFboId()); auto compose_task = self_pass.endRenderPass<GlDrawBlitTask>(program, currentPass()->getFboId());
compose_task->setRenderSize(static_cast<uint32_t>(gl_cmp->bbox.w), static_cast<uint32_t>(gl_cmp->bbox.h));
compose_task->setPrevTask(prev_task);
prepareCmpTask(compose_task, gl_cmp->bbox); prepareCmpTask(compose_task, gl_cmp->bbox, self_pass.getFboWidth(), self_pass.getFboHeight());
{ {
uint32_t loc = program->getUniformLocation("uSrcTexture"); uint32_t loc = program->getUniformLocation("uSrcTexture");
@ -1025,16 +1158,19 @@ void GlRenderer::endRenderPass(Compositor* cmp)
} }
compose_task->setDrawDepth(currentPass()->nextDrawDepth()); compose_task->setDrawDepth(currentPass()->nextDrawDepth());
compose_task->setParentSize(static_cast<uint32_t>(currentPass()->getViewport().w), static_cast<uint32_t>(currentPass()->getViewport().h));
currentPass()->addRenderTask(compose_task); currentPass()->addRenderTask(compose_task);
} else { } else {
auto renderPass = std::move(mRenderPassStack.back()); auto renderPass = std::move(mRenderPassStack.back());
mRenderPassStack.pop_back(); mRenderPassStack.pop_back();
if (renderPass.isEmpty()) return;
auto task = renderPass.endRenderPass<GlDrawBlitTask>( auto task = renderPass.endRenderPass<GlDrawBlitTask>(
mPrograms[RT_Image].get(), currentPass()->getFboId()); mPrograms[RT_Image].get(), currentPass()->getFboId());
task->setRenderSize(static_cast<uint32_t>(gl_cmp->bbox.w), static_cast<uint32_t>(gl_cmp->bbox.h));
prepareCmpTask(task, gl_cmp->bbox); prepareCmpTask(task, gl_cmp->bbox, renderPass.getFboWidth(), renderPass.getFboHeight());
task->setDrawDepth(currentPass()->nextDrawDepth()); task->setDrawDepth(currentPass()->nextDrawDepth());
// matrix buffer // matrix buffer
@ -1073,7 +1209,7 @@ void GlRenderer::endRenderPass(Compositor* cmp)
uint32_t loc = task->getProgram()->getUniformLocation("uTexture"); uint32_t loc = task->getProgram()->getUniformLocation("uTexture");
task->addBindResource(GlBindingResource{0, renderPass.getTextureId(), loc}); task->addBindResource(GlBindingResource{0, renderPass.getTextureId(), loc});
} }
task->setParentSize(static_cast<uint32_t>(currentPass()->getViewport().w), static_cast<uint32_t>(currentPass()->getViewport().h));
currentPass()->addRenderTask(std::move(task)); currentPass()->addRenderTask(std::move(task));
} }
} }

View file

@ -25,6 +25,7 @@
#include <vector> #include <vector>
#include "tvgGlRenderTarget.h"
#include "tvgGlRenderTask.h" #include "tvgGlRenderTask.h"
#include "tvgGlGpuBuffer.h" #include "tvgGlGpuBuffer.h"
#include "tvgGlRenderPass.h" #include "tvgGlRenderPass.h"
@ -92,7 +93,7 @@ private:
GlRenderPass* currentPass(); GlRenderPass* currentPass();
void prepareBlitTask(GlBlitTask* task); void prepareBlitTask(GlBlitTask* task);
void prepareCmpTask(GlRenderTask* task, const RenderRegion& vp); void prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint32_t cmpWidth, uint32_t cmpHeight);
void endRenderPass(Compositor* cmp); void endRenderPass(Compositor* cmp);
Surface surface; Surface surface;
@ -102,7 +103,7 @@ private:
unique_ptr<GlStageBuffer> mGpuBuffer; unique_ptr<GlStageBuffer> mGpuBuffer;
vector<std::unique_ptr<GlProgram>> mPrograms; vector<std::unique_ptr<GlProgram>> mPrograms;
unique_ptr<GlRenderTarget> mRootTarget = {}; unique_ptr<GlRenderTarget> mRootTarget = {};
Array<GlRenderTarget*> mComposePool = {}; Array<GlRenderTargetPool*> mComposePool = {};
vector<GlRenderPass> mRenderPassStack = {}; vector<GlRenderPass> mRenderPassStack = {};
vector<unique_ptr<GlCompositor>> mComposeStack = {}; vector<unique_ptr<GlCompositor>> mComposeStack = {};