fixed version 3.3 and 4.3, support < 4.3

main
Benjamin Kraft 1 year ago
parent 05baa0db8a
commit b9e00628f3
  1. 4
      src/GLWidget.h
  2. 2
      src/MainWindow.cpp
  3. 88
      src/Simulation.cpp
  4. 6
      src/Simulation.h
  5. 2
      src/main.cpp

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <QOpenGLExtraFunctions> #include <QOpenGLFunctions_3_3_Core>
#include <QMatrix3x3> #include <QMatrix3x3>
class Pendulum; class Pendulum;
@ -9,7 +9,7 @@ class Simulation;
class QOpenGLShaderProgram; class QOpenGLShaderProgram;
class Overlay; class Overlay;
class GLWidget : public QOpenGLWidget, protected QOpenGLExtraFunctions { class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core {
public: public:
explicit GLWidget(Simulation *); explicit GLWidget(Simulation *);
Overlay * overlay; Overlay * overlay;

@ -383,13 +383,13 @@ QWidget * MainWindow::buildSimulationUI() {
// GPU-Acceleration // GPU-Acceleration
{ {
auto useGPU = new QCheckBox("Use GPU-Acceleration"); auto useGPU = new QCheckBox("Use GPU-Acceleration");
useGPU->setCheckState(Qt::Checked);
connect(useGPU, &QCheckBox::stateChanged, simulation, &Simulation::useGPUChanged); connect(useGPU, &QCheckBox::stateChanged, simulation, &Simulation::useGPUChanged);
connect(simulation, &Simulation::gpuNotSupported, [useGPU](const std::string &message){ connect(simulation, &Simulation::gpuNotSupported, [useGPU](const std::string &message){
useGPU->setCheckState(Qt::Unchecked); useGPU->setCheckState(Qt::Unchecked);
useGPU->setEnabled(false); useGPU->setEnabled(false);
useGPU->setToolTip(QString::fromStdString(message)); useGPU->setToolTip(QString::fromStdString(message));
}); });
useGPU->setCheckState(Qt::Unchecked);
lyt->addWidget(useGPU); lyt->addWidget(useGPU);
} }

@ -24,14 +24,21 @@ void Simulation::initialize() {
// OpenGL Offscreen functions // OpenGL Offscreen functions
{ {
auto context = new QOpenGLContext(this); auto context = new QOpenGLContext(this);
context->setFormat(QSurfaceFormat::defaultFormat()); auto format = QSurfaceFormat::defaultFormat();
format.setVersion(4, 3);
context->setFormat(format);
context->create(); context->create();
auto surface = new QOffscreenSurface(nullptr, this); auto surface = new QOffscreenSurface(nullptr, this);
surface->setFormat(context->format()); surface->setFormat(context->format());
surface->create(); surface->create();
context->makeCurrent(surface); context->makeCurrent(surface);
initializeOpenGLFunctions(); f = new QOpenGLFunctions_4_3_Core;
if (!context->hasExtension("GL_ARB_gpu_shader_fp64")){ if (!f->initializeOpenGLFunctions()){
std::string message = "OpenGL 4.3 is required for Compute Shaders! Falling back to CPU-Multithreading.";
printf("%s\n", message.c_str());
useGPUAcceleration = false;
emit gpuNotSupported(message);
} else if (!context->hasExtension("GL_ARB_gpu_shader_fp64")){
std::string message = "Double precision not supported by OpenGL! Falling back to CPU-Multithreading."; std::string message = "Double precision not supported by OpenGL! Falling back to CPU-Multithreading.";
printf("%s\n", message.c_str()); printf("%s\n", message.c_str());
useGPUAcceleration = false; useGPUAcceleration = false;
@ -39,13 +46,16 @@ void Simulation::initialize() {
} }
} }
if (!useGPUAcceleration)
return;
// Read GPU Limits // Read GPU Limits
{ {
for (int i = 0; i < 3; i++){ for (int i = 0; i < 3; i++){
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, i, gpuLimits.maxWGCount + i); f->glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, i, gpuLimits.maxWGCount + i);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, i, gpuLimits.maxWGSize + i); f->glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, i, gpuLimits.maxWGSize + i);
} }
glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &gpuLimits.maxWGInvocations); f->glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &gpuLimits.maxWGInvocations);
printf("Max work group count: (%d, %d, %d)\n", gpuLimits.maxWGCount[0], gpuLimits.maxWGCount[1], gpuLimits.maxWGCount[2]); printf("Max work group count: (%d, %d, %d)\n", gpuLimits.maxWGCount[0], gpuLimits.maxWGCount[1], gpuLimits.maxWGCount[2]);
printf("Max work group size: (%d, %d, %d)\n", gpuLimits.maxWGSize[0], gpuLimits.maxWGSize[1], gpuLimits.maxWGSize[2]); printf("Max work group size: (%d, %d, %d)\n", gpuLimits.maxWGSize[0], gpuLimits.maxWGSize[1], gpuLimits.maxWGSize[2]);
@ -58,13 +68,13 @@ void Simulation::initialize() {
program->addShaderFromSourceFile(QOpenGLShader::Compute, ":/shaders/compute.glsl"); program->addShaderFromSourceFile(QOpenGLShader::Compute, ":/shaders/compute.glsl");
program->link(); program->link();
glGenBuffers(6, &SSBO.positions); f->glGenBuffers(6, &SSBO.positions);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, SSBO.positions); f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, SSBO.positions);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, SSBO.velocities); f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, SSBO.velocities);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, SSBO.invMasses); f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, SSBO.invMasses);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, SSBO.lengths); f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, SSBO.lengths);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, SSBO.indices); f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, SSBO.indices);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, SSBO.segmentCounts); f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, SSBO.segmentCounts);
} }
} }
@ -100,18 +110,18 @@ void Simulation::updateGPUData() {
auto indicesSize = GLsizeiptr(indices.size() * sizeof(GLuint)); auto indicesSize = GLsizeiptr(indices.size() * sizeof(GLuint));
auto segmentCountsSize = GLsizeiptr(segmentCounts.size() * sizeof(GLuint)); auto segmentCountsSize = GLsizeiptr(segmentCounts.size() * sizeof(GLuint));
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.positions); f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.positions);
glBufferData(GL_SHADER_STORAGE_BUFFER, posSize, positions.data(), GL_DYNAMIC_DRAW); f->glBufferData(GL_SHADER_STORAGE_BUFFER, posSize, positions.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities);
glBufferData(GL_SHADER_STORAGE_BUFFER, velSize, velocities.data(), GL_DYNAMIC_DRAW); f->glBufferData(GL_SHADER_STORAGE_BUFFER, velSize, velocities.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.invMasses); f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.invMasses);
glBufferData(GL_SHADER_STORAGE_BUFFER, invMassSize, invMasses.data(), GL_STATIC_DRAW); f->glBufferData(GL_SHADER_STORAGE_BUFFER, invMassSize, invMasses.data(), GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.lengths); f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.lengths);
glBufferData(GL_SHADER_STORAGE_BUFFER, lengthSize, lengths.data(), GL_STATIC_DRAW); f->glBufferData(GL_SHADER_STORAGE_BUFFER, lengthSize, lengths.data(), GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.indices); f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.indices);
glBufferData(GL_SHADER_STORAGE_BUFFER, indicesSize, indices.data(), GL_STATIC_DRAW); f->glBufferData(GL_SHADER_STORAGE_BUFFER, indicesSize, indices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.segmentCounts); f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.segmentCounts);
glBufferData(GL_SHADER_STORAGE_BUFFER, segmentCountsSize, segmentCounts.data(), GL_STATIC_DRAW); f->glBufferData(GL_SHADER_STORAGE_BUFFER, segmentCountsSize, segmentCounts.data(), GL_STATIC_DRAW);
} }
// Every few milliseconds // Every few milliseconds
@ -130,17 +140,17 @@ void Simulation::update() {
if (useGPUAcceleration) { if (useGPUAcceleration) {
program->bind(); program->bind();
glUniform1d(program->uniformLocation("h"), h); f->glUniform1d(program->uniformLocation("h"), h);
glUniform1d(program->uniformLocation("gravity"), gravity); f->glUniform1d(program->uniformLocation("gravity"), gravity);
glUniform1ui(program->uniformLocation("substeps"), substeps); f->glUniform1ui(program->uniformLocation("substeps"), substeps);
glDispatchCompute(pendula.size(), 1, 1); f->glDispatchCompute(pendula.size(), 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); f->glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
// Read updated positions // Read updated positions
{ {
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.positions); f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.positions);
auto * newPositions = (double*) glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); auto * newPositions = (double*) f->glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
int index = 0; int index = 0;
for (Pendulum * p : pendula){ for (Pendulum * p : pendula){
for (Vector &point : p->X){ for (Vector &point : p->X){
@ -148,13 +158,13 @@ void Simulation::update() {
point.y = newPositions[index++]; point.y = newPositions[index++];
} }
} }
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); f->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
} }
// Read updated velocities // Read updated velocities
{ {
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities);
auto * newVelocities = (double*) glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); auto * newVelocities = (double*) f->glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
int index = 0; int index = 0;
for (Pendulum * p : pendula){ for (Pendulum * p : pendula){
for (Vector &velocity : p->V){ for (Vector &velocity : p->V){
@ -162,7 +172,7 @@ void Simulation::update() {
velocity.y = newVelocities[index++]; velocity.y = newVelocities[index++];
} }
} }
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); f->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
} }
#pragma omp parallel for #pragma omp parallel for
@ -208,7 +218,8 @@ void Simulation::clearPendula() {
pendula.shrink_to_fit(); pendula.shrink_to_fit();
updateEnergy(); updateEnergy();
updateGPUData(); if (useGPUAcceleration)
updateGPUData();
emit layoutChanged(); emit layoutChanged();
} }
@ -220,7 +231,8 @@ void Simulation::addPendula(const std::vector<Pendulum *> &add) {
pendula.push_back(p); pendula.push_back(p);
updateEnergy(); updateEnergy();
updateGPUData(); if (useGPUAcceleration)
updateGPUData();
emit layoutChanged(); emit layoutChanged();
} }

@ -5,11 +5,12 @@
#include <semaphore> #include <semaphore>
#include <QOpenGLFunctions_4_3_Core> #include <QOpenGLFunctions_4_3_Core>
class QTimer;
class FPS; class FPS;
class Pendulum; class Pendulum;
class QOpenGLShaderProgram; class QOpenGLShaderProgram;
class Simulation : public QObject, protected QOpenGLFunctions_4_3_Core { class Simulation : public QObject {
Q_OBJECT Q_OBJECT
public: public:
explicit Simulation(); explicit Simulation();
@ -42,6 +43,7 @@ public slots:
private slots: private slots:
void update(); void update();
private: private:
QOpenGLFunctions_4_3_Core * f;
void updateGPUData(); void updateGPUData();
struct GPULimits { struct GPULimits {
int maxWGCount[3]; int maxWGCount[3];
@ -59,5 +61,5 @@ private:
} SSBO; } SSBO;
QTimer * timer; QTimer * timer;
int updateInterval = 16; int updateInterval = 16;
bool useGPUAcceleration = false; bool useGPUAcceleration = true;
}; };

@ -8,7 +8,7 @@ int main(int argc, char* argv[]) {
fmt.setDepthBufferSize(24); fmt.setDepthBufferSize(24);
fmt.setSamples(8); fmt.setSamples(8);
fmt.setSwapInterval(1); fmt.setSwapInterval(1);
fmt.setVersion(4, 3); fmt.setVersion(3, 3);
fmt.setProfile(QSurfaceFormat::CoreProfile); fmt.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(fmt); QSurfaceFormat::setDefaultFormat(fmt);

Loading…
Cancel
Save