Skip to content

Commit 64aeb40

Browse files
committed
Parallelise GLElementGroup display list rebuild
1 parent 808fcb5 commit 64aeb40

3 files changed

Lines changed: 283 additions & 42 deletions

File tree

src/fea/src/gl_element.cpp

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
void GLElement::_init(const GLElement *pGlElement)
1010
{
11+
this->pPrecomputed = nullptr; // never copy the precomputed pointer
1112
if (pGlElement)
1213
{
1314
this->pointVolume = pGlElement->pointVolume;
@@ -60,8 +61,158 @@ void GLElement::setSurfaceThickness(double surfaceThickness)
6061
this->surfaceThickness = surfaceThickness;
6162
}
6263

64+
void GLElement::setPrecomputedData(const GLElementPrecomputedData *pData)
65+
{
66+
this->pPrecomputed = pData;
67+
}
68+
69+
GLElementPrecomputedData GLElement::precompute() const
70+
{
71+
GLElementPrecomputedData data;
72+
if (!this->pModel)
73+
{
74+
return data;
75+
}
76+
77+
data.type = this->getType();
78+
data.useGlCullFace = this->getUseGlCullFace();
79+
data.pointVolume = this->pointVolume;
80+
data.lineCrossArea = this->lineCrossArea;
81+
data.surfaceThickness = this->surfaceThickness;
82+
data.color = this->color;
83+
84+
// Fetch node positions
85+
uint nn = this->size();
86+
data.nodes.resize(nn);
87+
for (uint i = 0; i < nn; i++)
88+
{
89+
data.nodes[i] = this->pModel->getNode(this->getNodeId(i)).toVector();
90+
}
91+
92+
// Apply displacement
93+
if (this->pDisplacementVariable)
94+
{
95+
std::vector<RR3Vector> dispValues;
96+
this->findDisplacementNodeValues(this->elementID, *this->pDisplacementVariable, dispValues);
97+
if (dispValues.size() == nn)
98+
{
99+
for (uint i = 0; i < nn; i++)
100+
{
101+
RNode n(data.nodes[i]);
102+
n.move(dispValues[i]);
103+
data.nodes[i] = n.toVector();
104+
}
105+
}
106+
}
107+
108+
// Scalar texture coordinates
109+
if (this->pScalarVariable)
110+
{
111+
this->findScalarNodeValues(this->elementID, *this->pScalarVariable, data.textureCoords);
112+
}
113+
114+
// Edge node flags (tetrahedra only)
115+
if (data.type == R_ELEMENT_TETRA1)
116+
{
117+
data.edgeNodes.resize(nn);
118+
for (uint i = 0; i < nn; i++)
119+
{
120+
data.edgeNodes[i] = this->pModel->nodeIsOnEdge(this->getNodeId(i));
121+
}
122+
}
123+
124+
// Draw mask (assumes GL_ELEMENT_DRAW_NORMAL mode)
125+
if (this->elementGroupData.getDrawWire())
126+
{
127+
data.drawMask |= GLSimplex::Wired;
128+
}
129+
else
130+
{
131+
data.drawMask |= GLSimplex::Normal;
132+
}
133+
if (this->elementGroupData.getDrawEdges())
134+
{
135+
data.drawMask |= GLSimplex::ElementEdges;
136+
}
137+
if (this->elementGroupData.getDrawNodes())
138+
{
139+
data.drawMask |= GLSimplex::ElementNodes;
140+
}
141+
142+
data.valid = true;
143+
return data;
144+
}
145+
146+
void GLElement::drawFromPrecomputed(const GLElementPrecomputedData &data)
147+
{
148+
switch (data.type)
149+
{
150+
case R_ELEMENT_POINT:
151+
{
152+
GLSimplexPoint point(this->getGLWidget(), data.nodes, data.pointVolume);
153+
if (!data.textureCoords.empty())
154+
{
155+
point.setNodeTextureCoordinates(data.textureCoords);
156+
}
157+
point.setDrawType(data.drawMask);
158+
point.setColor(data.color);
159+
point.paint();
160+
break;
161+
}
162+
case R_ELEMENT_TRUSS1:
163+
{
164+
GLSimplexSegment segment(this->getGLWidget(), data.nodes, data.lineCrossArea);
165+
if (!data.textureCoords.empty())
166+
{
167+
segment.setNodeTextureCoordinates(data.textureCoords);
168+
}
169+
segment.setDrawType(data.drawMask);
170+
segment.setColor(data.color);
171+
segment.paint();
172+
break;
173+
}
174+
case R_ELEMENT_TRI1:
175+
case R_ELEMENT_QUAD1:
176+
{
177+
GLSimplexPolygon polygon(this->getGLWidget(), data.nodes, data.surfaceThickness);
178+
polygon.setUseGlCullFace(data.useGlCullFace);
179+
if (!data.textureCoords.empty())
180+
{
181+
polygon.setNodeTextureCoordinates(data.textureCoords);
182+
}
183+
polygon.setDrawType(data.drawMask);
184+
polygon.setColor(data.color);
185+
polygon.paint();
186+
break;
187+
}
188+
case R_ELEMENT_TETRA1:
189+
{
190+
GLSimplexTetrahedra tetra(this->getGLWidget(), data.nodes);
191+
if (!data.edgeNodes.empty())
192+
{
193+
tetra.setEdgeNodes(data.edgeNodes);
194+
}
195+
if (!data.textureCoords.empty())
196+
{
197+
tetra.setNodeTextureCoordinates(data.textureCoords);
198+
}
199+
tetra.setDrawType(data.drawMask);
200+
tetra.setColor(data.color);
201+
tetra.paint();
202+
break;
203+
}
204+
default:
205+
break;
206+
}
207+
}
208+
63209
void GLElement::draw()
64210
{
211+
if (this->pPrecomputed)
212+
{
213+
this->drawFromPrecomputed(*this->pPrecomputed);
214+
return;
215+
}
65216
if (!this->pModel)
66217
{
67218
return;

src/fea/src/gl_element.h

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,33 @@
66
#include "gl_object.h"
77
#include "gl_element_base.h"
88

9+
//! Pre-computed per-element data: pure CPU results that can be computed in
10+
//! parallel (read-only model access) before the serial GL recording phase.
11+
struct GLElementPrecomputedData
12+
{
13+
bool valid; //!< false → skip this element in the draw phase
14+
RElementType type; //!< element geometry type
15+
std::vector<RR3Vector> nodes; //!< final node positions (displacement applied)
16+
std::vector<double> textureCoords; //!< per-node scalar texture coords (empty if none)
17+
std::vector<bool> edgeNodes; //!< per-node edge flags (tetrahedra only)
18+
QColor color;
19+
int drawMask;
20+
bool useGlCullFace;
21+
double pointVolume;
22+
double lineCrossArea;
23+
double surfaceThickness;
24+
25+
GLElementPrecomputedData()
26+
: valid(false)
27+
, type(R_ELEMENT_POINT)
28+
, drawMask(0)
29+
, useGlCullFace(false)
30+
, pointVolume(0.0)
31+
, lineCrossArea(0.0)
32+
, surfaceThickness(0.0)
33+
{}
34+
};
35+
936
class GLElement : public GLElementBase, public RElement
1037
{
1138

@@ -17,6 +44,8 @@ class GLElement : public GLElementBase, public RElement
1744
double lineCrossArea;
1845
//! Surface thickness.
1946
double surfaceThickness;
47+
//! Optional pre-computed data (not owned; valid for one paint() call).
48+
const GLElementPrecomputedData *pPrecomputed;
2049

2150
private:
2251

@@ -46,11 +75,21 @@ class GLElement : public GLElementBase, public RElement
4675
//! Set surface thickness.
4776
void setSurfaceThickness(double surfaceThickness);
4877

78+
//! Set pre-computed data pointer (not owned; must outlive the paint() call).
79+
void setPrecomputedData(const GLElementPrecomputedData *pData);
80+
81+
//! Pre-compute element data (node positions, scalar values, edge flags).
82+
//! Pure CPU work — safe to call from a worker thread.
83+
GLElementPrecomputedData precompute() const;
84+
4985
protected:
5086

51-
//! Draw scene.
87+
//! Draw scene (uses pPrecomputed if set, otherwise recomputes on the fly).
5288
void draw();
5389

90+
//! Draw directly from pre-computed data (no model access; GL calls only).
91+
void drawFromPrecomputed(const GLElementPrecomputedData &data);
92+
5493
//! Draw point.
5594
void drawPoint();
5695

0 commit comments

Comments
 (0)