|
|
|
@ -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<Pendulum *> &add) { |
|
|
|
|
pendula.push_back(p); |
|
|
|
|
|
|
|
|
|
updateEnergy(); |
|
|
|
|
updateGPUData(); |
|
|
|
|
if (useGPUAcceleration) |
|
|
|
|
updateGPUData(); |
|
|
|
|
|
|
|
|
|
emit layoutChanged(); |
|
|
|
|
} |
|
|
|
|