mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
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:
parent
53a570e680
commit
76f98008e8
11 changed files with 479 additions and 173 deletions
|
@ -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',
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
132
src/renderer/gl_engine/tvgGlRenderTarget.cpp
Normal file
132
src/renderer/gl_engine/tvgGlRenderTarget.cpp
Normal 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;
|
||||||
|
}
|
69
src/renderer/gl_engine/tvgGlRenderTarget.h
Normal file
69
src/renderer/gl_engine/tvgGlRenderTarget.h
Normal 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_
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = {};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue