aboutsummaryrefslogtreecommitdiffstats
path: root/gui
diff options
context:
space:
mode:
authorMateusz Zalega <mateusz@appliedsourcery.com>2018-08-16 21:44:37 +0200
committerMateusz Zalega <mateusz@appliedsourcery.com>2018-10-23 15:43:51 +0200
commitd03291eeb1efbb1005eba5a8a4b2c92ef66d2fd5 (patch)
tree997b4a31291efaca2d1f60c54e95b81785a9ddcc /gui
parentb5faa7ad102b8308eeb0c73a3849909bf4b1b635 (diff)
downloadnextpnr-d03291eeb1efbb1005eba5a8a4b2c92ef66d2fd5.tar.gz
nextpnr-d03291eeb1efbb1005eba5a8a4b2c92ef66d2fd5.tar.bz2
nextpnr-d03291eeb1efbb1005eba5a8a4b2c92ef66d2fd5.zip
gui: improved FPGAViewWidget::paintGL() performance
Profiling revealed that memcpy() in QOpenGLBuffer::allocate() had been taking the most time during paintGL() calls. I've been able to take the CPU usage down to about 1/4 of its previous values by caching elements in VBOs and updating them only after subsequent calls to renderGraphicElement(). Signed-off-by: Mateusz Zalega <mateusz@appliedsourcery.com>
Diffstat (limited to 'gui')
-rw-r--r--gui/fpgaviewwidget.cc96
-rw-r--r--gui/fpgaviewwidget.h1
-rw-r--r--gui/lineshader.cc123
-rw-r--r--gui/lineshader.h32
4 files changed, 166 insertions, 86 deletions
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc
index 3b0b3df7..fb5e36b2 100644
--- a/gui/fpgaviewwidget.cc
+++ b/gui/fpgaviewwidget.cc
@@ -103,8 +103,21 @@ void FPGAViewWidget::initializeGL()
log_error("Could not compile shader.\n");
}
initializeOpenGLFunctions();
- glClearColor(colors_.background.red() / 255, colors_.background.green() / 255, colors_.background.blue() / 255,
- 0.0);
+ glClearColor(colors_.background.red() / 255, colors_.background.green() / 255,
+ colors_.background.blue() / 255, 0.0);
+
+
+ {
+ QMutexLocker locker(&rendererDataLock_);
+ // Render grid.
+ auto grid = LineShaderData();
+ for (float i = -100.0f; i < 100.0f; i += 1.0f) {
+ PolyLine(-100.0f, i, 100.0f, i).build(grid);
+ PolyLine(i, -100.0f, i, 100.0f).build(grid);
+ }
+ grid.last_render = 1;
+ lineShader_.update_vbos(GraphicElement::STYLE_GRID, grid);
+ }
}
float FPGAViewWidget::PickedElement::distance(Context *ctx, float wx, float wy) const
@@ -185,6 +198,8 @@ void FPGAViewWidget::renderGraphicElement(LineShaderData &out, PickQuadTree::Bou
bb.setY0(std::min(bb.y0(), y + el.y1));
bb.setX1(std::max(bb.x1(), x + el.x2));
bb.setY1(std::max(bb.y1(), y + el.y2));
+
+ out.last_render++;
return;
}
@@ -194,6 +209,8 @@ void FPGAViewWidget::renderGraphicElement(LineShaderData &out, PickQuadTree::Bou
bb.setY0(std::min(bb.y0(), y + el.y1));
bb.setX1(std::max(bb.x1(), x + el.x2));
bb.setY1(std::max(bb.y1(), y + el.y2));
+
+ out.last_render++;
return;
}
}
@@ -297,36 +314,40 @@ void FPGAViewWidget::paintGL()
float thick11Px = mouseToWorldDimensions(1.1, 0).x();
float thick2Px = mouseToWorldDimensions(2, 0).x();
- // Render grid.
- auto grid = LineShaderData();
- for (float i = -100.0f; i < 100.0f; i += 1.0f) {
- PolyLine(-100.0f, i, 100.0f, i).build(grid);
- PolyLine(i, -100.0f, i, 100.0f).build(grid);
- }
- // Flags from pipeline.
- PassthroughFlags flags;
- // Draw grid.
- lineShader_.draw(grid, colors_.grid, thick1Px, matrix);
-
{
QMutexLocker locker(&rendererDataLock_);
+ // Must be called from a thread holding the OpenGL context
+ update_vbos();
+ }
- // Render Arch graphics.
- lineShader_.draw(rendererData_->gfxByStyle[GraphicElement::STYLE_FRAME], colors_.frame, thick11Px, matrix);
- lineShader_.draw(rendererData_->gfxByStyle[GraphicElement::STYLE_HIDDEN], colors_.hidden, thick11Px, matrix);
- lineShader_.draw(rendererData_->gfxByStyle[GraphicElement::STYLE_INACTIVE], colors_.inactive, thick11Px,
- matrix);
- lineShader_.draw(rendererData_->gfxByStyle[GraphicElement::STYLE_ACTIVE], colors_.active, thick11Px, matrix);
-
- // Draw highlighted items.
- for (int i = 0; i < 8; i++)
- lineShader_.draw(rendererData_->gfxHighlighted[i], colors_.highlight[i], thick11Px, matrix);
+ // Render the grid.
+ lineShader_.draw(GraphicElement::STYLE_GRID, colors_.grid, thick1Px,
+ matrix);
+
+ // Render Arch graphics.
+ lineShader_.draw(GraphicElement::STYLE_FRAME, colors_.frame, thick11Px,
+ matrix);
+ lineShader_.draw(GraphicElement::STYLE_HIDDEN, colors_.hidden, thick11Px,
+ matrix);
+ lineShader_.draw(GraphicElement::STYLE_INACTIVE, colors_.inactive,
+ thick11Px, matrix);
+ lineShader_.draw(GraphicElement::STYLE_ACTIVE, colors_.active, thick11Px,
+ matrix);
+
+ // Draw highlighted items.
+ for (int i = 0; i < 8; i++) {
+ GraphicElement::style_t style = (GraphicElement::style_t)(
+ GraphicElement::STYLE_HIGHLIGHTED0 + i);
+ lineShader_.draw(style, colors_.highlight[i], thick11Px, matrix);
+ }
- lineShader_.draw(rendererData_->gfxSelected, colors_.selected, thick11Px, matrix);
- lineShader_.draw(rendererData_->gfxHovered, colors_.hovered, thick2Px, matrix);
+ lineShader_.draw(GraphicElement::STYLE_SELECTED, colors_.selected,
+ thick11Px, matrix);
+ lineShader_.draw(GraphicElement::STYLE_HOVER, colors_.hovered,
+ thick2Px, matrix);
- flags = rendererData_->flags;
- }
+ // Flags from pipeline.
+ PassthroughFlags flags = rendererData_->flags;
// Check flags passed through pipeline.
if (flags.zoomOutbound) {
@@ -799,4 +820,25 @@ void FPGAViewWidget::leaveEvent(QEvent *event)
pokeRenderer();
}
+void FPGAViewWidget::update_vbos()
+{
+ for (int style = GraphicElement::STYLE_FRAME; style
+ < GraphicElement::STYLE_HIGHLIGHTED0;
+ style++) {
+ lineShader_.update_vbos((enum GraphicElement::style_t)(style),
+ rendererData_->gfxByStyle[style]);
+ }
+
+ for (int i = 0; i < 8; i++) {
+ GraphicElement::style_t style = (GraphicElement::style_t)(
+ GraphicElement::STYLE_HIGHLIGHTED0 + i);
+ lineShader_.update_vbos(style, rendererData_->gfxHighlighted[i]);
+ }
+
+ lineShader_.update_vbos(GraphicElement::STYLE_SELECTED,
+ rendererData_->gfxSelected);
+ lineShader_.update_vbos(GraphicElement::STYLE_HOVER,
+ rendererData_->gfxHovered);
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h
index 4be41bf5..697ace21 100644
--- a/gui/fpgaviewwidget.h
+++ b/gui/fpgaviewwidget.h
@@ -304,6 +304,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
QVector4D mouseToWorldCoordinates(int x, int y);
QVector4D mouseToWorldDimensions(float x, float y);
QMatrix4x4 getProjection(void);
+ void update_vbos();
};
NEXTPNR_NAMESPACE_END
diff --git a/gui/lineshader.cc b/gui/lineshader.cc
index eba96020..0f762b38 100644
--- a/gui/lineshader.cc
+++ b/gui/lineshader.cc
@@ -162,75 +162,114 @@ bool LineShader::compile(void)
return false;
}
- if (!vao_.create())
- log_abort();
- vao_.bind();
-
- if (!buffers_.position.create())
- log_abort();
- if (!buffers_.normal.create())
- log_abort();
- if (!buffers_.miter.create())
- log_abort();
- if (!buffers_.index.create())
- log_abort();
-
+ program_->bind();
attributes_.position = program_->attributeLocation("position");
attributes_.normal = program_->attributeLocation("normal");
attributes_.miter = program_->attributeLocation("miter");
uniforms_.thickness = program_->uniformLocation("thickness");
uniforms_.projection = program_->uniformLocation("projection");
uniforms_.color = program_->uniformLocation("color");
+ program_->release();
+
+ for (int style = 0; style < GraphicElement::STYLE_MAX; style++) {
+ buffers_[style].position = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
+ buffers_[style].normal = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
+ buffers_[style].miter = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
+ buffers_[style].index = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
+
+ if (!buffers_[style].vao.create())
+ log_abort();
+ buffers_[style].vao.bind();
+
+ if (!buffers_[style].position.create())
+ log_abort();
+ if (!buffers_[style].normal.create())
+ log_abort();
+ if (!buffers_[style].miter.create())
+ log_abort();
+ if (!buffers_[style].index.create())
+ log_abort();
+
+ buffers_[style].position.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ buffers_[style].normal.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ buffers_[style].miter.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ buffers_[style].index.setUsagePattern(QOpenGLBuffer::StaticDraw);
+
+ buffers_[style].position.bind();
+ buffers_[style].normal.bind();
+ buffers_[style].miter.bind();
+ buffers_[style].index.bind();
+
+ buffers_[style].vao.release();
+ }
- vao_.release();
return true;
}
-void LineShader::draw(const LineShaderData &line, const QColor &color, float thickness, const QMatrix4x4 &projection)
+void LineShader::update_vbos(enum GraphicElement::style_t style,
+ const LineShaderData &line)
{
- auto gl = QOpenGLContext::currentContext()->functions();
- if (line.vertices.size() == 0)
+ if (buffers_[style].last_vbo_update == line.last_render)
return;
- vao_.bind();
- program_->bind();
+ buffers_[style].last_vbo_update = line.last_render;
+
+ buffers_[style].indices = line.indices.size();
+ if (buffers_[style].indices == 0) {
+ // invalidate buffers
+ buffers_[style].position.allocate(nullptr, 0);
+ buffers_[style].normal.allocate(nullptr, 0);
+ buffers_[style].miter.allocate(nullptr, 0);
+ buffers_[style].index.allocate(nullptr, 0);
+ return;
+ }
+
+ buffers_[style].position.bind();
+ buffers_[style].position.allocate(&line.vertices[0], sizeof(Vertex2DPOD) * line.vertices.size());
- buffers_.position.bind();
- buffers_.position.allocate(&line.vertices[0], sizeof(Vertex2DPOD) * line.vertices.size());
+ buffers_[style].normal.bind();
+ buffers_[style].normal.allocate(&line.normals[0], sizeof(Vertex2DPOD) * line.normals.size());
- buffers_.normal.bind();
- buffers_.normal.allocate(&line.normals[0], sizeof(Vertex2DPOD) * line.normals.size());
+ buffers_[style].miter.bind();
+ buffers_[style].miter.allocate(&line.miters[0], sizeof(GLfloat) * line.miters.size());
- buffers_.miter.bind();
- buffers_.miter.allocate(&line.miters[0], sizeof(GLfloat) * line.miters.size());
+ buffers_[style].index.bind();
+ buffers_[style].index.allocate(&line.indices[0], sizeof(GLuint) * line.indices.size());
+}
- buffers_.index.bind();
- buffers_.index.allocate(&line.indices[0], sizeof(GLuint) * line.indices.size());
+void LineShader::draw(enum GraphicElement::style_t style, const QColor &color,
+ float thickness, const QMatrix4x4 &projection)
+{
+ auto gl = QOpenGLContext::currentContext()->functions();
+ if (buffers_[style].indices == 0)
+ return;
+ program_->bind();
+ buffers_[style].vao.bind();
program_->setUniformValue(uniforms_.projection, projection);
program_->setUniformValue(uniforms_.thickness, thickness);
program_->setUniformValue(uniforms_.color, color.redF(), color.greenF(), color.blueF(), color.alphaF());
- buffers_.position.bind();
- program_->enableAttributeArray("position");
- gl->glVertexAttribPointer(attributes_.position, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
+ buffers_[style].position.bind();
+ program_->enableAttributeArray(attributes_.position);
+ program_->setAttributeBuffer(attributes_.position, GL_FLOAT, 0, 2);
- buffers_.normal.bind();
- program_->enableAttributeArray("normal");
- gl->glVertexAttribPointer(attributes_.normal, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
+ buffers_[style].normal.bind();
+ program_->enableAttributeArray(attributes_.normal);
+ program_->setAttributeBuffer(attributes_.normal, GL_FLOAT, 0, 2);
- buffers_.miter.bind();
- program_->enableAttributeArray("miter");
- gl->glVertexAttribPointer(attributes_.miter, 1, GL_FLOAT, GL_FALSE, 0, (void *)0);
+ buffers_[style].miter.bind();
+ program_->enableAttributeArray(attributes_.miter);
+ program_->setAttributeBuffer(attributes_.miter, GL_FLOAT, 0, 1);
- buffers_.index.bind();
- gl->glDrawElements(GL_TRIANGLES, line.indices.size(), GL_UNSIGNED_INT, (void *)0);
+ buffers_[style].index.bind();
+ gl->glDrawElements(GL_TRIANGLES, buffers_[style].indices, GL_UNSIGNED_INT, (void *)0);
- program_->disableAttributeArray("miter");
- program_->disableAttributeArray("normal");
- program_->disableAttributeArray("position");
+ program_->disableAttributeArray(attributes_.position);
+ program_->disableAttributeArray(attributes_.normal);
+ program_->disableAttributeArray(attributes_.miter);
+ buffers_[style].vao.release();
program_->release();
- vao_.release();
}
NEXTPNR_NAMESPACE_END
diff --git a/gui/lineshader.h b/gui/lineshader.h
index 3f4c4057..eb0f9e09 100644
--- a/gui/lineshader.h
+++ b/gui/lineshader.h
@@ -20,12 +20,14 @@
#ifndef LINESHADER_H
#define LINESHADER_H
+#include <array>
#include <QOpenGLBuffer>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLWidget>
+#include "log.h"
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -49,7 +51,7 @@ struct LineShaderData
std::vector<GLfloat> miters;
std::vector<GLuint> indices;
- LineShaderData(void) {}
+ int last_render = 0;
void clear(void)
{
@@ -142,13 +144,18 @@ class LineShader
} attributes_;
// GL buffers
- struct
+ struct Buffers
{
QOpenGLBuffer position;
QOpenGLBuffer normal;
QOpenGLBuffer miter;
QOpenGLBuffer index;
- } buffers_;
+ QOpenGLVertexArrayObject vao;
+ int indices = 0;
+
+ int last_vbo_update = 0;
+ };
+ std::array<Buffers, GraphicElement::STYLE_MAX> buffers_;
// GL uniform locations.
struct
@@ -161,22 +168,9 @@ class LineShader
GLuint color;
} uniforms_;
- QOpenGLVertexArrayObject vao_;
-
public:
LineShader(QObject *parent) : parent_(parent), program_(nullptr)
{
- buffers_.position = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
- buffers_.position.setUsagePattern(QOpenGLBuffer::StaticDraw);
-
- buffers_.normal = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
- buffers_.normal.setUsagePattern(QOpenGLBuffer::StaticDraw);
-
- buffers_.miter = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
- buffers_.miter.setUsagePattern(QOpenGLBuffer::StaticDraw);
-
- buffers_.index = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
- buffers_.index.setUsagePattern(QOpenGLBuffer::StaticDraw);
}
static constexpr const char *vertexShaderSource_ =
@@ -200,8 +194,12 @@ class LineShader
// Must be called on initialization.
bool compile(void);
+ void update_vbos(enum GraphicElement::style_t style,
+ const LineShaderData &line);
+
// Render a LineShaderData with a given M/V/P transformation.
- void draw(const LineShaderData &data, const QColor &color, float thickness, const QMatrix4x4 &projection);
+ void draw(enum GraphicElement::style_t style, const QColor &color,
+ float thickness, const QMatrix4x4 &projection);
};
NEXTPNR_NAMESPACE_END