diff --git a/src/GLWidget.h b/src/GLWidget.h index ff52e0c..f8257aa 100644 --- a/src/GLWidget.h +++ b/src/GLWidget.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include class Pendulum; @@ -9,7 +9,7 @@ class Simulation; class QOpenGLShaderProgram; class Overlay; -class GLWidget : public QOpenGLWidget, protected QOpenGLExtraFunctions { +class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core { public: explicit GLWidget(Simulation *); Overlay * overlay; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 39356e2..6c139b2 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -383,13 +383,13 @@ QWidget * MainWindow::buildSimulationUI() { // GPU-Acceleration { auto useGPU = new QCheckBox("Use GPU-Acceleration"); + useGPU->setCheckState(Qt::Checked); connect(useGPU, &QCheckBox::stateChanged, simulation, &Simulation::useGPUChanged); connect(simulation, &Simulation::gpuNotSupported, [useGPU](const std::string &message){ useGPU->setCheckState(Qt::Unchecked); useGPU->setEnabled(false); useGPU->setToolTip(QString::fromStdString(message)); }); - useGPU->setCheckState(Qt::Unchecked); lyt->addWidget(useGPU); } diff --git a/src/Simulation.cpp b/src/Simulation.cpp index 9d77b9d..3b1df2f 100644 --- a/src/Simulation.cpp +++ b/src/Simulation.cpp @@ -24,14 +24,21 @@ void Simulation::initialize() { // OpenGL Offscreen functions { auto context = new QOpenGLContext(this); - context->setFormat(QSurfaceFormat::defaultFormat()); + auto format = QSurfaceFormat::defaultFormat(); + format.setVersion(4, 3); + context->setFormat(format); context->create(); auto surface = new QOffscreenSurface(nullptr, this); surface->setFormat(context->format()); surface->create(); context->makeCurrent(surface); - initializeOpenGLFunctions(); - if (!context->hasExtension("GL_ARB_gpu_shader_fp64")){ + f = new QOpenGLFunctions_4_3_Core; + 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."; printf("%s\n", message.c_str()); useGPUAcceleration = false; @@ -39,13 +46,16 @@ void Simulation::initialize() { } } + if (!useGPUAcceleration) + return; + // Read GPU Limits { for (int i = 0; i < 3; i++){ - 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_COUNT, i, gpuLimits.maxWGCount + 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 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->link(); - glGenBuffers(6, &SSBO.positions); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, SSBO.positions); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, SSBO.velocities); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, SSBO.invMasses); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, SSBO.lengths); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, SSBO.indices); - glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, SSBO.segmentCounts); + f->glGenBuffers(6, &SSBO.positions); + f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, SSBO.positions); + f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, SSBO.velocities); + f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, SSBO.invMasses); + f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, SSBO.lengths); + f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, SSBO.indices); + f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, SSBO.segmentCounts); } } @@ -100,18 +110,18 @@ void Simulation::updateGPUData() { auto indicesSize = GLsizeiptr(indices.size() * sizeof(GLuint)); auto segmentCountsSize = GLsizeiptr(segmentCounts.size() * sizeof(GLuint)); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.positions); - glBufferData(GL_SHADER_STORAGE_BUFFER, posSize, positions.data(), GL_DYNAMIC_DRAW); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); - glBufferData(GL_SHADER_STORAGE_BUFFER, velSize, velocities.data(), GL_DYNAMIC_DRAW); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.invMasses); - glBufferData(GL_SHADER_STORAGE_BUFFER, invMassSize, invMasses.data(), GL_STATIC_DRAW); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.lengths); - glBufferData(GL_SHADER_STORAGE_BUFFER, lengthSize, lengths.data(), GL_STATIC_DRAW); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.indices); - glBufferData(GL_SHADER_STORAGE_BUFFER, indicesSize, indices.data(), GL_STATIC_DRAW); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.segmentCounts); - glBufferData(GL_SHADER_STORAGE_BUFFER, segmentCountsSize, segmentCounts.data(), GL_STATIC_DRAW); + f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.positions); + f->glBufferData(GL_SHADER_STORAGE_BUFFER, posSize, positions.data(), GL_DYNAMIC_DRAW); + f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); + f->glBufferData(GL_SHADER_STORAGE_BUFFER, velSize, velocities.data(), GL_DYNAMIC_DRAW); + f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.invMasses); + f->glBufferData(GL_SHADER_STORAGE_BUFFER, invMassSize, invMasses.data(), GL_STATIC_DRAW); + f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.lengths); + f->glBufferData(GL_SHADER_STORAGE_BUFFER, lengthSize, lengths.data(), GL_STATIC_DRAW); + f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.indices); + f->glBufferData(GL_SHADER_STORAGE_BUFFER, indicesSize, indices.data(), GL_STATIC_DRAW); + f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.segmentCounts); + f->glBufferData(GL_SHADER_STORAGE_BUFFER, segmentCountsSize, segmentCounts.data(), GL_STATIC_DRAW); } // Every few milliseconds @@ -130,17 +140,17 @@ void Simulation::update() { if (useGPUAcceleration) { program->bind(); - glUniform1d(program->uniformLocation("h"), h); - glUniform1d(program->uniformLocation("gravity"), gravity); - glUniform1ui(program->uniformLocation("substeps"), substeps); + f->glUniform1d(program->uniformLocation("h"), h); + f->glUniform1d(program->uniformLocation("gravity"), gravity); + f->glUniform1ui(program->uniformLocation("substeps"), substeps); - glDispatchCompute(pendula.size(), 1, 1); - glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); + f->glDispatchCompute(pendula.size(), 1, 1); + f->glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); // Read updated positions { - glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.positions); - auto * newPositions = (double*) glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); + f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.positions); + auto * newPositions = (double*) f->glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); int index = 0; for (Pendulum * p : pendula){ for (Vector &point : p->X){ @@ -148,13 +158,13 @@ void Simulation::update() { point.y = newPositions[index++]; } } - glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); + f->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); } // Read updated velocities { - glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); - auto * newVelocities = (double*) glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); + f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); + auto * newVelocities = (double*) f->glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY); int index = 0; for (Pendulum * p : pendula){ for (Vector &velocity : p->V){ @@ -162,7 +172,7 @@ void Simulation::update() { velocity.y = newVelocities[index++]; } } - glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); + f->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); } #pragma omp parallel for @@ -208,7 +218,8 @@ void Simulation::clearPendula() { pendula.shrink_to_fit(); updateEnergy(); - updateGPUData(); + if (useGPUAcceleration) + updateGPUData(); emit layoutChanged(); } @@ -220,7 +231,8 @@ void Simulation::addPendula(const std::vector &add) { pendula.push_back(p); updateEnergy(); - updateGPUData(); + if (useGPUAcceleration) + updateGPUData(); emit layoutChanged(); } diff --git a/src/Simulation.h b/src/Simulation.h index 6af7bbe..73f947b 100644 --- a/src/Simulation.h +++ b/src/Simulation.h @@ -5,11 +5,12 @@ #include #include +class QTimer; class FPS; class Pendulum; class QOpenGLShaderProgram; -class Simulation : public QObject, protected QOpenGLFunctions_4_3_Core { +class Simulation : public QObject { Q_OBJECT public: explicit Simulation(); @@ -42,6 +43,7 @@ public slots: private slots: void update(); private: + QOpenGLFunctions_4_3_Core * f; void updateGPUData(); struct GPULimits { int maxWGCount[3]; @@ -59,5 +61,5 @@ private: } SSBO; QTimer * timer; int updateInterval = 16; - bool useGPUAcceleration = false; + bool useGPUAcceleration = true; }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 70b48ce..3293be6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,7 @@ int main(int argc, char* argv[]) { fmt.setDepthBufferSize(24); fmt.setSamples(8); fmt.setSwapInterval(1); - fmt.setVersion(4, 3); + fmt.setVersion(3, 3); fmt.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(fmt);