Optimized text rendering

dev
Tomasz Kapuściński 2022-02-05 21:07:25 +01:00
parent aacc2d0596
commit 0d612b9928
4 changed files with 67 additions and 36 deletions

View File

@ -77,6 +77,7 @@ public:
virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) = 0;
virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) = 0;
virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) = 0;
virtual bool EndPrimitive() = 0;
};

View File

@ -136,26 +136,23 @@ public:
renderer->SetTexture(Texture{ m_texID });
renderer->SetTransparency(m_transparency);
assert(m_firsts.size() == m_counts.size());
if (m_firsts.size() < m_quads.size())
if (m_counts.size() < m_quads.size())
{
// m_firsts needs to look like { 0, 4, 8, 12, ... }
// m_counts needs to look like { 4, 4, 4, 4, ... }
// and both need to be the same length as m_quads
m_counts.resize(m_quads.size(), 4);
std::size_t begin = m_firsts.size();
m_firsts.resize(m_quads.size());
for (std::size_t i = begin; i < m_firsts.size(); ++i)
{
m_firsts[i] = static_cast<int>(4 * i);
}
}
auto vertices = renderer->BeginPrimitives(PrimitiveType::TRIANGLE_STRIP, m_quads.size(), m_counts.data());
size_t offset = 0;
for (const auto& quad : m_quads)
{
renderer->DrawPrimitive(PrimitiveType::TRIANGLE_STRIP, 4, quad.vertices);
std::copy_n(quad.vertices, 4, vertices + offset);
offset += 4;
}
renderer->EndPrimitive();
m_engine.AddStatisticTriangle(static_cast<int>(m_quads.size() * 2));
m_quads.clear();
}
@ -164,7 +161,6 @@ private:
struct Quad { Vertex2D vertices[4]; };
std::vector<Quad> m_quads;
std::vector<int> m_firsts;
std::vector<int> m_counts;
Color m_color;
@ -1050,18 +1046,14 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, glm::iv
Gfx::IntColor col = Gfx::ColorToIntColor(color);
auto renderer = m_device->GetUIRenderer();
renderer->SetTransparency(TransparencyMode::WHITE);
renderer->SetTexture(Texture{ texID });
auto vertices = renderer->BeginPrimitive(PrimitiveType::TRIANGLE_STRIP, 4);
Gfx::Vertex2D vertices[4];
vertices[0] = { { p1.x, p2.y }, { uv1.x, uv2.y }, col };
vertices[1] = { { p1.x, p1.y }, { uv1.x, uv1.y }, col };
vertices[2] = { { p2.x, p2.y }, { uv2.x, uv2.y }, col };
vertices[3] = { { p2.x, p1.y }, { uv2.x, uv1.y }, col };
//m_quadBatch->Add(quad, texID, TransparencyMode::WHITE, color);
renderer->EndPrimitive();
m_quadBatch->Add(vertices, texID, TransparencyMode::WHITE, color);
pos.x += width;
}
@ -1092,18 +1084,14 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, glm::iv
Gfx::IntColor col = Gfx::ColorToIntColor(color);
auto renderer = m_device->GetUIRenderer();
renderer->SetTransparency(TransparencyMode::ALPHA);
renderer->SetTexture(Texture{ tex.id });
auto vertices = renderer->BeginPrimitive(PrimitiveType::TRIANGLE_STRIP, 4);
Gfx::Vertex2D vertices[4];
vertices[0] = { { p1.x, p2.y }, { texCoord1.x, texCoord2.y }, col };
vertices[1] = { { p1.x, p1.y }, { texCoord1.x, texCoord1.y }, col };
vertices[2] = { { p2.x, p2.y }, { texCoord2.x, texCoord2.y }, col };
vertices[3] = { { p2.x, p1.y }, { texCoord2.x, texCoord1.y }, col };
//m_quadBatch->Add(quad, tex.id, TransparencyMode::ALPHA, color);
renderer->EndPrimitive();
m_quadBatch->Add(vertices, tex.id, TransparencyMode::ALPHA, color);
pos.x += tex.charSize.x * width;
}

View File

@ -147,18 +147,30 @@ void CGL33UIRenderer::DrawPrimitive(PrimitiveType type, int count, const Vertex2
}
Vertex2D* CGL33UIRenderer::BeginPrimitive(PrimitiveType type, int count)
{
return BeginPrimitives(type, 1, &count);
}
Vertex2D* CGL33UIRenderer::BeginPrimitives(PrimitiveType type, int drawCount, const int* counts)
{
glBindVertexArray(m_bufferVAO);
glBindBuffer(GL_ARRAY_BUFFER, m_bufferVBO);
GLuint total = m_offset + count;
m_currentCount = 0;
for (size_t i = 0; i < drawCount; i++)
{
m_currentCount += counts[i];
}
GLuint total = m_bufferOffset + m_currentCount;
// Buffer full, orphan
if (total >= m_bufferCapacity)
{
glBufferData(GL_ARRAY_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW);
m_offset = 0;
m_bufferOffset = 0;
// Respecify vertex attributes
glEnableVertexAttribArray(0);
@ -174,20 +186,33 @@ Vertex2D* CGL33UIRenderer::BeginPrimitive(PrimitiveType type, int count)
reinterpret_cast<void*>(offsetof(Vertex2D, color)));
}
m_first.resize(drawCount);
m_count.resize(drawCount);
GLsizei currentOffset = m_bufferOffset;
for (size_t i = 0; i < drawCount; i++)
{
m_first[i] = currentOffset;
m_count[i] = counts[i];
currentOffset += counts[i];
}
auto ptr = glMapBufferRange(GL_ARRAY_BUFFER,
m_offset * sizeof(Vertex2D),
count * sizeof(Vertex2D),
m_bufferOffset * sizeof(Vertex2D),
m_currentCount * sizeof(Vertex2D),
GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
m_mapped = true;
m_type = type;
m_count = count;
m_drawCount = drawCount;
// Mapping failed, use backup buffer
if (ptr == nullptr)
{
m_backup = true;
m_buffer.resize(count);
m_buffer.resize(m_currentCount);
return m_buffer.data();
}
@ -203,7 +228,10 @@ bool CGL33UIRenderer::EndPrimitive()
if (m_backup)
{
glBufferSubData(GL_ARRAY_BUFFER, m_offset * sizeof(Vertex2D), m_count * sizeof(Vertex2D), m_buffer.data());
glBufferSubData(GL_ARRAY_BUFFER,
m_bufferOffset * sizeof(Vertex2D),
m_currentCount * sizeof(Vertex2D),
m_buffer.data());
}
else
{
@ -218,9 +246,12 @@ bool CGL33UIRenderer::EndPrimitive()
m_device->SetDepthTest(false);
glDrawArrays(TranslateGfxPrimitive(m_type), m_offset, m_count);
if (m_drawCount == 1)
glDrawArrays(TranslateGfxPrimitive(m_type), m_first.front(), m_count.front());
else
glMultiDrawArrays(TranslateGfxPrimitive(m_type), m_first.data(), m_count.data(), m_drawCount);
m_offset += m_count;
m_bufferOffset += m_currentCount;
m_mapped = false;
m_backup = false;

View File

@ -51,6 +51,7 @@ public:
virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) override;
virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) override;
virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) override;
virtual bool EndPrimitive() override;
private:
@ -78,12 +79,22 @@ private:
GLuint m_bufferVAO = 0;
// VBO capacity
GLsizei m_bufferCapacity = 128 * 1024;
// Buffer offset
GLsizei m_bufferOffset = 0;
// Buffer mapping state
PrimitiveType m_type = {};
GLuint m_offset = 0;
GLuint m_count = 0;
// Number of drawn primitives
GLuint m_drawCount = 0;
// Total count of drawn vertices
GLuint m_currentCount = 0;
// Starting offset for each drawn primitive
std::vector<GLint> m_first;
// Numbers of vertices for each drawn primitive
std::vector<GLsizei> m_count;
// True means currently drawing
bool m_mapped = false;
// True means mapping failed, using auxiliary buffer
bool m_backup = false;
// Buffered vertex data