|
|
@ -32,7 +32,10 @@ void Simulation::initialize() { |
|
|
|
context->makeCurrent(surface); |
|
|
|
context->makeCurrent(surface); |
|
|
|
initializeOpenGLFunctions(); |
|
|
|
initializeOpenGLFunctions(); |
|
|
|
if (!context->hasExtension("GL_ARB_gpu_shader_fp64")){ |
|
|
|
if (!context->hasExtension("GL_ARB_gpu_shader_fp64")){ |
|
|
|
printf("Double precision not supported by OpenGL!\n"); |
|
|
|
std::string message = "Double precision not supported by OpenGL! Falling back to CPU-Multithreading."; |
|
|
|
|
|
|
|
printf("%s\n", message.c_str()); |
|
|
|
|
|
|
|
useGPUAcceleration = false; |
|
|
|
|
|
|
|
emit gpuNotSupported(message); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -58,7 +61,7 @@ void Simulation::initialize() { |
|
|
|
glGenBuffers(6, &SSBO.positions); |
|
|
|
glGenBuffers(6, &SSBO.positions); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, SSBO.positions); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, SSBO.positions); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, SSBO.velocities); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, SSBO.velocities); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, SSBO.masses); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, SSBO.invMasses); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, SSBO.lengths); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, SSBO.lengths); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, SSBO.indices); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, SSBO.indices); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, SSBO.segmentCounts); |
|
|
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, SSBO.segmentCounts); |
|
|
@ -70,7 +73,7 @@ void Simulation::initialize() { |
|
|
|
void Simulation::updateGPUData() { |
|
|
|
void Simulation::updateGPUData() { |
|
|
|
std::vector<GLdouble> positions; |
|
|
|
std::vector<GLdouble> positions; |
|
|
|
std::vector<GLdouble> velocities; |
|
|
|
std::vector<GLdouble> velocities; |
|
|
|
std::vector<GLdouble> masses; |
|
|
|
std::vector<GLdouble> invMasses; |
|
|
|
std::vector<GLdouble> lengths; |
|
|
|
std::vector<GLdouble> lengths; |
|
|
|
std::vector<GLuint> indices; |
|
|
|
std::vector<GLuint> indices; |
|
|
|
std::vector<GLuint> segmentCounts; |
|
|
|
std::vector<GLuint> segmentCounts; |
|
|
@ -81,18 +84,18 @@ void Simulation::updateGPUData() { |
|
|
|
currentIndex += p->X.size(); |
|
|
|
currentIndex += p->X.size(); |
|
|
|
segmentCounts.push_back(p->X.size()); |
|
|
|
segmentCounts.push_back(p->X.size()); |
|
|
|
for (size_t i = 0; i < p->X.size(); i++){ |
|
|
|
for (size_t i = 0; i < p->X.size(); i++){ |
|
|
|
positions.push_back(GLdouble(p->X[i].x)); |
|
|
|
positions.push_back(p->X[i].x); |
|
|
|
positions.push_back(GLdouble(p->X[i].y)); |
|
|
|
positions.push_back(p->X[i].y); |
|
|
|
velocities.push_back(GLdouble(p->V[i].x)); |
|
|
|
velocities.push_back(p->V[i].x); |
|
|
|
velocities.push_back(GLdouble(p->V[i].y)); |
|
|
|
velocities.push_back(p->V[i].y); |
|
|
|
masses.push_back(GLfloat(p->M[i])); |
|
|
|
invMasses.push_back(1.0 / p->M[i]); |
|
|
|
lengths.push_back(GLfloat(p->L[i])); |
|
|
|
lengths.push_back(p->L[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
auto posSize = GLsizeiptr(positions.size() * sizeof(GLdouble)); |
|
|
|
auto posSize = GLsizeiptr(positions.size() * sizeof(GLdouble)); |
|
|
|
auto velSize = GLsizeiptr(velocities.size() * sizeof(GLdouble)); |
|
|
|
auto velSize = GLsizeiptr(velocities.size() * sizeof(GLdouble)); |
|
|
|
auto massSize = GLsizeiptr(masses.size() * sizeof(GLdouble)); |
|
|
|
auto invMassSize = GLsizeiptr(invMasses.size() * sizeof(GLdouble)); |
|
|
|
auto lengthSize = GLsizeiptr(lengths.size() * sizeof(GLdouble)); |
|
|
|
auto lengthSize = GLsizeiptr(lengths.size() * sizeof(GLdouble)); |
|
|
|
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)); |
|
|
@ -101,8 +104,8 @@ void Simulation::updateGPUData() { |
|
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, posSize, positions.data(), GL_DYNAMIC_DRAW); |
|
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, posSize, positions.data(), GL_DYNAMIC_DRAW); |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); |
|
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, velSize, velocities.data(), GL_DYNAMIC_DRAW); |
|
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, velSize, velocities.data(), GL_DYNAMIC_DRAW); |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.masses); |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.invMasses); |
|
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, massSize, masses.data(), GL_STATIC_DRAW); |
|
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, invMassSize, invMasses.data(), GL_STATIC_DRAW); |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.lengths); |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.lengths); |
|
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, lengthSize, lengths.data(), GL_STATIC_DRAW); |
|
|
|
glBufferData(GL_SHADER_STORAGE_BUFFER, lengthSize, lengths.data(), GL_STATIC_DRAW); |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.indices); |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.indices); |
|
|
@ -125,33 +128,12 @@ void Simulation::update() { |
|
|
|
double newPotentialEnergy = 0; |
|
|
|
double newPotentialEnergy = 0; |
|
|
|
double newKineticEnergy = 0; |
|
|
|
double newKineticEnergy = 0; |
|
|
|
|
|
|
|
|
|
|
|
auto t1 = system_clock::now(); |
|
|
|
if (useGPUAcceleration) { |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
// OLD with CPUs
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
#pragma omp parallel for |
|
|
|
|
|
|
|
for (int i = 0; i < pendula.size(); i++){ // NOLINT(*-loop-convert) // not ranged based for msvc
|
|
|
|
|
|
|
|
for (int k = 0; k < substeps; k++) |
|
|
|
|
|
|
|
pendula[i]->update(h, gravity); |
|
|
|
|
|
|
|
double localPotentialEnergy = pendula[i]->potentialEnergy(gravity); |
|
|
|
|
|
|
|
double localKineticEnergy = pendula[i]->kineticEnergy(); |
|
|
|
|
|
|
|
#pragma omp atomic |
|
|
|
|
|
|
|
newPotentialEnergy += localPotentialEnergy; |
|
|
|
|
|
|
|
#pragma omp atomic |
|
|
|
|
|
|
|
newKineticEnergy += localKineticEnergy; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NEW with GPUs
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
program->bind(); |
|
|
|
program->bind(); |
|
|
|
glUniform1d(program->uniformLocation("h"), h); |
|
|
|
glUniform1d(program->uniformLocation("h"), h); |
|
|
|
glUniform1d(program->uniformLocation("gravity"), gravity); |
|
|
|
glUniform1d(program->uniformLocation("gravity"), gravity); |
|
|
|
glUniform1ui(program->uniformLocation("substeps"), substeps); |
|
|
|
glUniform1ui(program->uniformLocation("substeps"), substeps); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glDispatchCompute(pendula.size(), 1, 1); |
|
|
|
glDispatchCompute(pendula.size(), 1, 1); |
|
|
|
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); |
|
|
|
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); |
|
|
|
|
|
|
|
|
|
|
@ -168,6 +150,7 @@ void Simulation::update() { |
|
|
|
} |
|
|
|
} |
|
|
|
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
|
|
|
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Read updated velocities
|
|
|
|
// Read updated velocities
|
|
|
|
{ |
|
|
|
{ |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); |
|
|
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, SSBO.velocities); |
|
|
@ -181,10 +164,31 @@ void Simulation::update() { |
|
|
|
} |
|
|
|
} |
|
|
|
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
|
|
|
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << duration_cast<microseconds>(system_clock::now() - t1).count() << std::endl; |
|
|
|
#pragma omp parallel for |
|
|
|
|
|
|
|
for (int i = 0; i < pendula.size(); i++){ // NOLINT(*-loop-convert) not ranged based for msvc
|
|
|
|
|
|
|
|
double localPotentialEnergy = pendula[i]->potentialEnergy(gravity); |
|
|
|
|
|
|
|
double localKineticEnergy = pendula[i]->kineticEnergy(); |
|
|
|
|
|
|
|
#pragma omp atomic |
|
|
|
|
|
|
|
newPotentialEnergy += localPotentialEnergy; |
|
|
|
|
|
|
|
#pragma omp atomic |
|
|
|
|
|
|
|
newKineticEnergy += localKineticEnergy; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// CPU-Multithreading
|
|
|
|
|
|
|
|
#pragma omp parallel for |
|
|
|
|
|
|
|
for (int i = 0; i < pendula.size(); i++){ // NOLINT(*-loop-convert) not ranged based for msvc
|
|
|
|
|
|
|
|
for (int k = 0; k < substeps; k++) |
|
|
|
|
|
|
|
pendula[i]->update(h, gravity); |
|
|
|
|
|
|
|
double localPotentialEnergy = pendula[i]->potentialEnergy(gravity); |
|
|
|
|
|
|
|
double localKineticEnergy = pendula[i]->kineticEnergy(); |
|
|
|
|
|
|
|
#pragma omp atomic |
|
|
|
|
|
|
|
newPotentialEnergy += localPotentialEnergy; |
|
|
|
|
|
|
|
#pragma omp atomic |
|
|
|
|
|
|
|
newKineticEnergy += localKineticEnergy; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
potentialEnergy = newPotentialEnergy; |
|
|
|
potentialEnergy = newPotentialEnergy; |
|
|
|
kineticEnergy = newKineticEnergy; |
|
|
|
kineticEnergy = newKineticEnergy; |
|
|
@ -229,3 +233,9 @@ void Simulation::updateEnergy() { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Simulation::useGPUChanged(int state) { |
|
|
|
|
|
|
|
useGPUAcceleration = state == Qt::Checked; |
|
|
|
|
|
|
|
if (useGPUAcceleration) |
|
|
|
|
|
|
|
updateGPUData(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|