Skip to content

Commit cceb32a

Browse files
committed
gl: reduce redundant per-draw setup
GL tasks repeat resource queries and state changes on each draw, even when the requested state is already active. Images and gradients pay the highest cost because they bind more resources. Benchmarks show image performance nearly doubles. Linear gradients improve by about 2.1x and radial gradients by about 1.7x, while pixel output and simple-geometry performance remain unchanged. Reuse renderer-owned state and immutable program lookups so each draw issues only the changes it needs. Invalidate mutable assumptions at sync boundaries and preserve the existing cleanup behavior. Callers sharing a GL context must rebind their own state after sync(). issue: thorvg#4555
1 parent b32227b commit cceb32a

21 files changed

Lines changed: 1194 additions & 522 deletions

src/renderer/gpu_engine/gl/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ source_file = [
1212
'tvgGlShader.h',
1313
'tvgGlShaderSrc.h',
1414
'tvgGlSolidBatch.h',
15+
'tvgGlStateCache.h',
1516
'tvgGlStencilCoverBatch.h',
1617
'tvgGl.cpp',
1718
'tvgGlEffect.cpp',
@@ -26,6 +27,7 @@ source_file = [
2627
'tvgGlRenderTask.cpp',
2728
'tvgGlShader.cpp',
2829
'tvgGlShaderSrc.cpp',
30+
'tvgGlStateCache.cpp',
2931
'tvgGlStencilCoverBatch.cpp',
3032
'tvgGlTessellator.cpp',
3133
'tvgGlTessellator.h',

src/renderer/gpu_engine/gl/tvgGl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@
259259
typedef void (*PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
260260
typedef void (*PFNGLCLEARSTENCILPROC)(GLint s);
261261
typedef void (*PFNGLCLEARDEPTHPROC)(GLdouble depth);
262-
typedef void (*PFNGLCLEARDEPTHFPROC)(GLdouble depth); // GLES
262+
typedef void (*PFNGLCLEARDEPTHFPROC)(GLfloat depth); // GLES
263263
typedef void (*PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
264264
typedef void (*PFNGLDEPTHMASKPROC)(GLboolean flag);
265265
typedef void (*PFNGLDISABLEPROC)(GLenum cap);

src/renderer/gpu_engine/gl/tvgGlCommon.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,20 @@
2929
#include "tvgMath.h"
3030
#include "tvgGpuCommon.h"
3131

32+
struct GlStageBuffer;
33+
struct GlRenderTask;
34+
3235
constexpr float MIN_GL_STROKE_WIDTH = 1.0f;
3336
constexpr float MIN_GL_STROKE_ALPHA = 0.25f;
3437

3538
constexpr uint32_t GL_MAT3_STD140_SIZE = 12; // mat3 is 3 vec4 columns in std140
3639
constexpr uint32_t GL_MAT3_STD140_BYTES = GL_MAT3_STD140_SIZE * sizeof(float);
3740

41+
// Texture allocation and parameter setup must choose a unit explicitly instead
42+
// of inheriting the last draw-time sampler unit. This unit is not reserved:
43+
// sampler 0 reuses it and the state cache restores its draw binding as needed.
44+
constexpr GLenum TVG_GL_TEXTURE_SETUP_UNIT = GL_TEXTURE0;
45+
3846
// All GPU matrices use column major order.
3947
static inline void getMatrix3(const Matrix& mat3, float* matOut)
4048
{
@@ -43,7 +51,6 @@ static inline void getMatrix3(const Matrix& mat3, float* matOut)
4351
matOut[2] = mat3.e31; matOut[5] = mat3.e32; matOut[8] = mat3.e33;
4452
}
4553

46-
4754
// All GPU matrices use column major order. std140 mat3 packs each column into a vec4 stride.
4855
static inline void getMatrix3Std140(const Matrix& mat3, float* matOut)
4956
{
@@ -53,18 +60,13 @@ static inline void getMatrix3Std140(const Matrix& mat3, float* matOut)
5360
matOut[3] = 0.0f; matOut[7] = 0.0f; matOut[11] = 0.0f;
5461
}
5562

56-
5763
enum class GlStencilMode {
5864
None,
5965
FillNonZero,
6066
FillEvenOdd,
6167
Stroke,
6268
};
6369

64-
65-
class GlStageBuffer;
66-
class GlRenderTask;
67-
6870
struct GlGeometryBuffer {
6971
Array<float> vertex;
7072
Array<uint32_t> index;

src/renderer/gpu_engine/gl/tvgGlEffect.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,15 @@ GlRenderTask* GlEffect::render(RenderEffectGaussianBlur* effect, GlRenderTarget*
8888
task->setViewport({{0, 0}, {vp.sw(), vp.sh()}});
8989
// horizontal blur task and geometry
9090
task->horzTask = new GlRenderTask(pBlurH);
91-
task->horzTask->addBindResource(GlBindingResource{0, pBlurH->getUniformBlockIndex("Gaussian"), gpuBuffer->getBufferId(), blurOffset, sizeof(GlGaussianBlur)});
92-
task->horzTask->addBindResource(GlBindingResource{1, pBlurH->getUniformBlockIndex("Viewport"), gpuBuffer->getBufferId(), viewportOffset, sizeof(viewport)});
93-
task->horzTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
91+
task->horzTask->addBindResource(GlBindingResource{0, GlShaderUniformBlock::Gaussian, gpuBuffer->getBufferId(), blurOffset, sizeof(GlGaussianBlur)});
92+
task->horzTask->addBindResource(GlBindingResource{1, GlShaderUniformBlock::Viewport, gpuBuffer->getBufferId(), viewportOffset, sizeof(viewport)});
93+
task->horzTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset, GL_FLOAT, GL_FALSE, gpuBuffer->getBufferId()});
9494
task->horzTask->setDrawRange(ioffset, 6);
9595
// vertical blur task and geometry
9696
task->vertTask = new GlRenderTask(pBlurV);
97-
task->vertTask->addBindResource(GlBindingResource{0, pBlurV->getUniformBlockIndex("Gaussian"), gpuBuffer->getBufferId(), blurOffset, sizeof(GlGaussianBlur)});
98-
task->vertTask->addBindResource(GlBindingResource{1, pBlurV->getUniformBlockIndex("Viewport"), gpuBuffer->getBufferId(), viewportOffset, sizeof(viewport)});
99-
task->vertTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
97+
task->vertTask->addBindResource(GlBindingResource{0, GlShaderUniformBlock::Gaussian, gpuBuffer->getBufferId(), blurOffset, sizeof(GlGaussianBlur)});
98+
task->vertTask->addBindResource(GlBindingResource{1, GlShaderUniformBlock::Viewport, gpuBuffer->getBufferId(), viewportOffset, sizeof(viewport)});
99+
task->vertTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset, GL_FLOAT, GL_FALSE, gpuBuffer->getBufferId()});
100100
task->vertTask->setDrawRange(ioffset, 6);
101101

102102
return task;
@@ -168,22 +168,22 @@ GlRenderTask* GlEffect::render(RenderEffectDropShadow* effect, GlRenderTarget* d
168168
auto task = new GlEffectDropShadowTask(pDropShadow, dstFbo, dstCopyFbo0, dstCopyFbo1);
169169
task->effect = (RenderEffectDropShadow*)effect;
170170
task->setViewport({{0, 0}, {vp.sw(), vp.sh()}});
171-
task->addBindResource(GlBindingResource{0, pDropShadow->getUniformBlockIndex("DropShadow"), gpuBuffer->getBufferId(), paramsOffset, sizeof(GlDropShadow)});
172-
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
171+
task->addBindResource(GlBindingResource{0, GlShaderUniformBlock::DropShadow, gpuBuffer->getBufferId(), paramsOffset, sizeof(GlDropShadow)});
172+
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset, GL_FLOAT, GL_FALSE, gpuBuffer->getBufferId()});
173173
task->setDrawRange(ioffset, 6);
174174

175175
// horizontal blur task and geometry
176176
task->horzTask = new GlRenderTask(pBlurH);
177-
task->horzTask->addBindResource(GlBindingResource{0, pBlurH->getUniformBlockIndex("Gaussian"), gpuBuffer->getBufferId(), paramsOffset, sizeof(GlGaussianBlur)});
178-
task->horzTask->addBindResource(GlBindingResource{1, pBlurH->getUniformBlockIndex("Viewport"), gpuBuffer->getBufferId(), viewportOffset, sizeof(viewport)});
179-
task->horzTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
177+
task->horzTask->addBindResource(GlBindingResource{0, GlShaderUniformBlock::Gaussian, gpuBuffer->getBufferId(), paramsOffset, sizeof(GlGaussianBlur)});
178+
task->horzTask->addBindResource(GlBindingResource{1, GlShaderUniformBlock::Viewport, gpuBuffer->getBufferId(), viewportOffset, sizeof(viewport)});
179+
task->horzTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset, GL_FLOAT, GL_FALSE, gpuBuffer->getBufferId()});
180180
task->horzTask->setDrawRange(ioffset, 6);
181181

182182
// vertical blur task and geometry
183183
task->vertTask = new GlRenderTask(pBlurV);
184-
task->vertTask->addBindResource(GlBindingResource{0, pBlurV->getUniformBlockIndex("Gaussian"), gpuBuffer->getBufferId(), paramsOffset, sizeof(GlGaussianBlur)});
185-
task->vertTask->addBindResource(GlBindingResource{1, pBlurV->getUniformBlockIndex("Viewport"), gpuBuffer->getBufferId(), viewportOffset, sizeof(viewport)});
186-
task->vertTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
184+
task->vertTask->addBindResource(GlBindingResource{0, GlShaderUniformBlock::Gaussian, gpuBuffer->getBufferId(), paramsOffset, sizeof(GlGaussianBlur)});
185+
task->vertTask->addBindResource(GlBindingResource{1, GlShaderUniformBlock::Viewport, gpuBuffer->getBufferId(), viewportOffset, sizeof(viewport)});
186+
task->vertTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset, GL_FLOAT, GL_FALSE, gpuBuffer->getBufferId()});
187187
task->vertTask->setDrawRange(ioffset, 6);
188188

189189
return task;
@@ -282,8 +282,8 @@ GlRenderTask* GlEffect::render(RenderEffect* effect, GlRenderTarget* dstFbo, Arr
282282
// create and setup task
283283
auto task = new GlEffectColorTransformTask(program, dstFbo, dstCopyFbo);
284284
task->setViewport({{0, 0}, {vp.sw(), vp.sh()}});
285-
task->addBindResource(GlBindingResource{0, program->getUniformBlockIndex("Params"), gpuBuffer->getBufferId(), paramsOffset, sizeof(GlEffectParams)});
286-
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
285+
task->addBindResource(GlBindingResource{0, GlShaderUniformBlock::Params, gpuBuffer->getBufferId(), paramsOffset, sizeof(GlEffectParams)});
286+
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset, GL_FLOAT, GL_FALSE, gpuBuffer->getBufferId()});
287287
task->setDrawRange(ioffset, 6);
288288

289289
return task;

src/renderer/gpu_engine/gl/tvgGlGeometry.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,14 @@ void GlGeometry::draw(GlRenderTask* task, GlStageBuffer* gpuBuffer, RenderUpdate
272272
auto buffer = ((flag & RenderUpdateFlag::Stroke) || (flag & RenderUpdateFlag::GradientStroke)) ? &stroke : &fill;
273273
auto vertexOffset = gpuBuffer->push(buffer->vertex.data, buffer->vertex.count * sizeof(float));
274274
auto indexOffset = gpuBuffer->pushIndex(buffer->index.data, buffer->index.count * sizeof(uint32_t));
275+
auto vertexBuffer = gpuBuffer->getBufferId();
275276

276277
if (flag & RenderUpdateFlag::Image) {
277278
// image has two attribute: [pos, uv]
278-
task->addVertexLayout(GlVertexLayout{0, 2, 4 * sizeof(float), vertexOffset});
279-
task->addVertexLayout(GlVertexLayout{1, 2, 4 * sizeof(float), vertexOffset + 2 * sizeof(float)});
279+
task->addVertexLayout(GlVertexLayout{0, 2, 4 * sizeof(float), vertexOffset, GL_FLOAT, GL_FALSE, vertexBuffer});
280+
task->addVertexLayout(GlVertexLayout{1, 2, 4 * sizeof(float), vertexOffset + 2 * sizeof(float), GL_FLOAT, GL_FALSE, vertexBuffer});
280281
} else {
281-
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), vertexOffset});
282+
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), vertexOffset, GL_FLOAT, GL_FALSE, vertexBuffer});
282283
}
283284
task->setDrawRange(indexOffset, buffer->index.count);
284285
}

src/renderer/gpu_engine/gl/tvgGlGpuBuffer.cpp

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,6 @@ void GlGpuBuffer::updateBufferData(Target target, uint32_t size, const void* dat
4545
}
4646

4747

48-
void GlGpuBuffer::bind(Target target)
49-
{
50-
GL_CHECK(glBindBuffer(static_cast<uint32_t>(target), mGlBufferId));
51-
}
52-
53-
54-
void GlGpuBuffer::unbind(Target target)
55-
{
56-
GL_CHECK(glBindBuffer(static_cast<uint32_t>(target), 0));
57-
}
58-
59-
6048
GlGpuBuffer::GlGpuBuffer()
6149
{
6250
GL_CHECK(glGenBuffers(1, &mGlBufferId));
@@ -156,8 +144,7 @@ uint32_t GlStageBuffer::reserveIndex(uint32_t size, void** dst)
156144
return offset;
157145
}
158146

159-
160-
bool GlStageBuffer::flushToGPU()
147+
bool GlStageBuffer::flushToGPU(GlStateCache& state)
161148
{
162149
if ((mStageBuffer.empty() && mAuxBuffer.empty()) || mIndexBuffer.empty()) {
163150
mStageBuffer.clear();
@@ -166,21 +153,20 @@ bool GlStageBuffer::flushToGPU()
166153
return false;
167154
}
168155

156+
state.bindVertexArray(mVao);
157+
169158
if (!mStageBuffer.empty()) {
170-
mGpuBuffer.bind(GlGpuBuffer::Target::ARRAY_BUFFER);
159+
state.bindBuffer(static_cast<uint32_t>(GlGpuBuffer::Target::ARRAY_BUFFER), mGpuBuffer.getBufferId());
171160
mGpuBuffer.updateBufferData(GlGpuBuffer::Target::ARRAY_BUFFER, mStageBuffer.count, mStageBuffer.data);
172-
mGpuBuffer.unbind(GlGpuBuffer::Target::ARRAY_BUFFER);
173161
}
174162

175163
if (!mAuxBuffer.empty()) {
176-
mGpuAuxBuffer.bind(GlGpuBuffer::Target::ARRAY_BUFFER);
164+
state.bindBuffer(static_cast<uint32_t>(GlGpuBuffer::Target::ARRAY_BUFFER), mGpuAuxBuffer.getBufferId());
177165
mGpuAuxBuffer.updateBufferData(GlGpuBuffer::Target::ARRAY_BUFFER, mAuxBuffer.count, mAuxBuffer.data);
178-
mGpuAuxBuffer.unbind(GlGpuBuffer::Target::ARRAY_BUFFER);
179166
}
180167

181-
mGpuIndexBuffer.bind(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER);
168+
state.bindBuffer(static_cast<uint32_t>(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER), mGpuIndexBuffer.getBufferId());
182169
mGpuIndexBuffer.updateBufferData(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER, mIndexBuffer.count, mIndexBuffer.data);
183-
mGpuIndexBuffer.unbind(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER);
184170

185171
mStageBuffer.clear();
186172
mAuxBuffer.clear();
@@ -189,22 +175,20 @@ bool GlStageBuffer::flushToGPU()
189175
return true;
190176
}
191177

192-
193-
void GlStageBuffer::bind()
178+
void GlStageBuffer::bind(GlStateCache& state)
194179
{
195-
glBindVertexArray(mVao);
196-
mGpuBuffer.bind(GlGpuBuffer::Target::ARRAY_BUFFER);
197-
mGpuBuffer.bind(GlGpuBuffer::Target::UNIFORM_BUFFER);
198-
mGpuIndexBuffer.bind(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER);
180+
state.bindVertexArray(mVao);
181+
state.bindBuffer(static_cast<uint32_t>(GlGpuBuffer::Target::ARRAY_BUFFER), mGpuBuffer.getBufferId());
182+
state.bindBuffer(static_cast<uint32_t>(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER), mGpuIndexBuffer.getBufferId());
199183
}
200184

201-
202-
void GlStageBuffer::unbind()
185+
void GlStageBuffer::unbind(GlStateCache& state)
203186
{
204-
glBindVertexArray(0);
205-
mGpuBuffer.unbind(GlGpuBuffer::Target::ARRAY_BUFFER);
206-
mGpuBuffer.unbind(GlGpuBuffer::Target::UNIFORM_BUFFER);
207-
mGpuIndexBuffer.unbind(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER);
187+
state.bindVertexArray(mVao);
188+
state.bindBuffer(static_cast<uint32_t>(GlGpuBuffer::Target::ARRAY_BUFFER), 0);
189+
GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, 0));
190+
state.bindBuffer(static_cast<uint32_t>(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER), 0);
191+
state.bindVertexArray(0);
208192
}
209193

210194

src/renderer/gpu_engine/gl/tvgGlGpuBuffer.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,19 @@
2424
#define _TVG_GL_GPU_BUFFER_H_
2525

2626
#include "tvgGlCommon.h"
27+
#include "tvgGlStateCache.h"
2728

2829
struct GlGpuBuffer
2930
{
3031
enum class Target
3132
{
3233
ARRAY_BUFFER = GL_ARRAY_BUFFER,
3334
ELEMENT_ARRAY_BUFFER = GL_ELEMENT_ARRAY_BUFFER,
34-
UNIFORM_BUFFER = GL_UNIFORM_BUFFER,
3535
};
3636

3737
GlGpuBuffer();
3838
~GlGpuBuffer();
3939
void updateBufferData(Target target, uint32_t size, const void* data);
40-
void bind(Target target);
41-
void unbind(Target target);
4240
uint32_t getBufferId() { return mGlBufferId; }
4341
private:
4442
uint32_t mGlBufferId = 0;
@@ -55,9 +53,9 @@ struct GlStageBuffer
5553
uint32_t reserve(uint32_t size, void** dst, bool alignGpuOffset = false);
5654
uint32_t reserveAux(uint32_t size, void** dst);
5755
uint32_t reserveIndex(uint32_t size, void** dst);
58-
bool flushToGPU();
59-
void bind();
60-
void unbind();
56+
bool flushToGPU(GlStateCache& state);
57+
void bind(GlStateCache& state);
58+
void unbind(GlStateCache& state);
6159
GLuint getBufferId();
6260
GLuint getAuxBufferId();
6361

@@ -74,4 +72,3 @@ struct GlStageBuffer
7472
};
7573

7674
#endif /* _TVG_GL_GPU_BUFFER_H_ */
77-

0 commit comments

Comments
 (0)