Commit 0fb2b6dd by Philipp Adolf

Merge branch '16-baue-neighbors-map-auf-der-gpu' into 'patchRender'

Resolve "Baue neighbors map auf der GPU" Closes #16 See merge request !7
parents beb432b2 5ed828b4
......@@ -7,6 +7,7 @@
<file>subdivide.vert</file>
<file>subdivision-copy.compute</file>
<file>subdivision-edge.compute</file>
<file>subdivision-neighbors.compute</file>
<file>subdivision-vertex.compute</file>
<file>subdivideRegular.tcs</file>
<file>subdivideRegular.tes</file>
......
#version 430 core
layout (local_size_x = 1, local_size_y = 1) in;
struct Vertex {
vec3 pos;
vec3 norm;
vec2 uv;
};
layout(std430, binding=0) buffer Vertices {
Vertex vb[];
};
layout(std430, binding=1) buffer Index {
unsigned int ib[];
};
layout(std430, binding=2) buffer Offset {
unsigned int offset_in;
unsigned int offset_search;
};
layout(std430, binding=3) buffer Output {
int neighbors[][3];
};
int shared_edge(vec3 u, vec3 v, vec3 w, vec3 a, vec3 b, vec3 c) {
if (u == a && v == c) {
return 0;
} else if (u == a && w == b) {
return 2;
} else if (v == a && w == c) {
return 1;
}
return -1;
}
void main() {
if (3 * (gl_GlobalInvocationID.x + offset_in) + 2 >= ib.length()) {
return;
}
int found = 0;
found += (neighbors[gl_GlobalInvocationID.x + offset_in][0] > 0) ? 1 : 0;
found += (neighbors[gl_GlobalInvocationID.x + offset_in][1] > 0) ? 1 : 0;
found += (neighbors[gl_GlobalInvocationID.x + offset_in][2] > 0) ? 1 : 0;
vec3 u = vb[ib[3 * (gl_GlobalInvocationID.x + offset_in) + 0]].pos;
vec3 v = vb[ib[3 * (gl_GlobalInvocationID.x + offset_in) + 1]].pos;
vec3 w = vb[ib[3 * (gl_GlobalInvocationID.x + offset_in) + 2]].pos;
for (int i = 0; found < 3 && i < 128 && (3 * gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i) + 2 < ib.length(); i++) {
vec3 a = vb[ib[3 * (gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i) + 0]].pos;
vec3 b = vb[ib[3 * (gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i) + 1]].pos;
vec3 c = vb[ib[3 * (gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i) + 2]].pos;
int edge;
edge = shared_edge(u, v, w, a, b, c);
if (edge < 0) {
edge = shared_edge(u, v, w, b, c, a);
}
if (edge < 0) {
edge = shared_edge(u, v, w, c, a, b);
}
if (edge >= 0) {
neighbors[gl_GlobalInvocationID.x + offset_in][edge] = int(gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i);
found++;
}
}
}
......@@ -10,6 +10,7 @@ Subdivision::Subdivision(QOpenGLFunctions_4_3_Core *f)
Subdivision::~Subdivision()
{
delete neighborsShader;
delete copyShader;
delete edgeShader;
delete vertexShader;
......@@ -22,7 +23,10 @@ QString Subdivision::formatTimeMeasurement(int time){
}
void Subdivision::init() {
QString source = QLatin1String(":/subdivision-copy.compute");
QString source = QLatin1String(":/subdivision-neighbors.compute");
neighborsShader = initComputeShaderProgram(source);
source = QLatin1String(":/subdivision-copy.compute");
copyShader = initComputeShaderProgram(source);
source = QLatin1String(":/subdivision-edge.compute");
......@@ -148,11 +152,9 @@ Subdivision::Tables Subdivision::precomputeTables(Input input) {
qCDebug(log_timing) << "building Triangles:" << formatTimeMeasurement(subTimer.elapsed());
subTimer.restart();
QMap<Triangle, Triangle::Neighbors> neighbors;
QVector<Triangle> all_triangles = triangles + triangles_regular;
buildNeighborsMap(all_triangles, neighbors);
qCDebug(log_timing) << "building neighbors map:" << formatTimeMeasurement(subTimer.elapsed());
buildNeighborsMap(vb, all_triangles, neighbors);
subTimer.restart();
precomputeEdgeTable(tables, triangles, neighbors, (unsigned int) vb.length());
......@@ -171,6 +173,176 @@ Subdivision::Tables Subdivision::precomputeTables(Input input) {
return tables;
}
void Subdivision::buildNeighborsMap(QVector<Vertex> &vb, QVector<Triangle> &triangles, QMap<Triangle, Triangle::Neighbors> &neighbors) {
QTime timer;
timer.start();
qCDebug(log_timing) << "buildNeighborsMap_gpu started";
QTime subTimer;
subTimer.start();
GLuint vb_handle;
f->glGenBuffers(1, &vb_handle);
f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, vb_handle);
f->glBufferData(GL_SHADER_STORAGE_BUFFER, vb.size() * sizeof(Vertex), vb.data(), GL_DYNAMIC_DRAW);
GLuint ib_handle;
f->glGenBuffers(1, &ib_handle);
f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, ib_handle);
f->glBufferData(GL_SHADER_STORAGE_BUFFER, triangles.size() * 3 * sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
GLuint *ptr = (GLuint *) f->glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY);
qDebug() << vb.size();
for (int i = 0; i < triangles.size(); i++) {
ptr[3 * i + 0] = triangles[i].u_idx();
ptr[3 * i + 1] = triangles[i].v_idx();
ptr[3 * i + 2] = triangles[i].w_idx();
}
f->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
GLuint offset_handle;
f->glGenBuffers(1, &offset_handle);
f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, offset_handle);
f->glBufferData(GL_SHADER_STORAGE_BUFFER, 2 * sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
GLuint output_handle;
f->glGenBuffers(1, &output_handle);
f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, output_handle);
f->glBufferData(GL_SHADER_STORAGE_BUFFER, triangles.size() * 3 * sizeof(GLint), NULL, GL_DYNAMIC_DRAW);
GLint *output_ptr = (GLint *) f->glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY);
memset(output_ptr, (GLint) -1, triangles.size() * 3 * sizeof(GLint));
f->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
qCDebug(log_timing) << "Copying to GPU:" << formatTimeMeasurement(subTimer.elapsed());
subTimer.restart();
neighborsShader->bind();
f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vb_handle);
f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ib_handle);
f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, offset_handle);
f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, output_handle);
GLuint offset_in = 0;
GLuint offset_search = 0;
while (offset_in <= (unsigned) triangles.size() || offset_search <= (unsigned) triangles.size()) {
if (offset_search > (unsigned) triangles.size()) {
offset_in += 128;
offset_search = 0;
}
f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, offset_handle);
GLuint *offset_ptr = (GLuint *) f->glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY);
offset_ptr[0] = offset_in;
offset_ptr[1] = offset_search;
f->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
qDebug() << "dispatching with offset" << offset_in << offset_search;
f->glDispatchCompute(128, 32, 1);
offset_search += 128 * 32;
}
f->glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, 0);
f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, 0);
f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, 0);
neighborsShader->release();
qCDebug(log_timing) << "Running shader:" << formatTimeMeasurement(subTimer.elapsed());
subTimer.restart();
f->glBindBuffer(GL_SHADER_STORAGE_BUFFER, output_handle);
GLint *out_ptr = (GLint *) f->glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_ONLY);
bool valid = true;
for (int i = 0; i < 3 * triangles.length(); i++) {
if (out_ptr[i] < 0 || out_ptr[i] >= triangles.length()) {
qCWarning(log_subdiv) << "Invalid neighbor:" << i << out_ptr[i];
valid = false;
}
}
if (valid) {
for (int i = 0; i < triangles.length(); i++) {
Triangle::Neighbors ns;
GLint other = out_ptr[3 * i + 0];
ns.uv.triangle = &(triangles[other]);
if (out_ptr[3 * other + 0] == i) {
ns.uv.edge.name = Triangle::Edge::Name::uv;
ns.uv.edge.a = ns.uv.triangle->u_idx();
ns.uv.edge.b = ns.uv.triangle->v_idx();
ns.uv.edge.c = ns.uv.triangle->w_idx();
} else if (out_ptr[3 * other + 1] == i) {
ns.uv.edge.name = Triangle::Edge::Name::vw;
ns.uv.edge.a = ns.uv.triangle->v_idx();
ns.uv.edge.b = ns.uv.triangle->w_idx();
ns.uv.edge.c = ns.uv.triangle->u_idx();
} else if (out_ptr[3 * other + 2] == i) {
ns.uv.edge.name = Triangle::Edge::Name::wu;
ns.uv.edge.a = ns.uv.triangle->w_idx();
ns.uv.edge.b = ns.uv.triangle->u_idx();
ns.uv.edge.c = ns.uv.triangle->v_idx();
}
other = out_ptr[3 * i + 1];
ns.vw.triangle = &(triangles[other]);
if (out_ptr[3 * other + 0] == i) {
ns.vw.edge.name = Triangle::Edge::Name::uv;
ns.vw.edge.a = ns.vw.triangle->u_idx();
ns.vw.edge.b = ns.vw.triangle->v_idx();
ns.vw.edge.c = ns.vw.triangle->w_idx();
} else if (out_ptr[3 * other + 1] == i) {
ns.vw.edge.name = Triangle::Edge::Name::vw;
ns.vw.edge.a = ns.vw.triangle->v_idx();
ns.vw.edge.b = ns.vw.triangle->w_idx();
ns.vw.edge.c = ns.vw.triangle->u_idx();
} else if (out_ptr[3 * other + 2] == i) {
ns.vw.edge.name = Triangle::Edge::Name::wu;
ns.vw.edge.a = ns.vw.triangle->w_idx();
ns.vw.edge.b = ns.vw.triangle->u_idx();
ns.vw.edge.c = ns.vw.triangle->v_idx();
}
other = out_ptr[3 * i + 2];
ns.wu.triangle = &(triangles[other]);
if (out_ptr[3 * other + 0] == i) {
ns.wu.edge.name = Triangle::Edge::Name::uv;
ns.wu.edge.a = ns.wu.triangle->u_idx();
ns.wu.edge.b = ns.wu.triangle->v_idx();
ns.wu.edge.c = ns.wu.triangle->w_idx();
} else if (out_ptr[3 * other + 1] == i) {
ns.wu.edge.name = Triangle::Edge::Name::vw;
ns.wu.edge.a = ns.wu.triangle->v_idx();
ns.wu.edge.b = ns.wu.triangle->w_idx();
ns.wu.edge.c = ns.wu.triangle->u_idx();
} else if (out_ptr[3 * other + 2] == i) {
ns.wu.edge.name = Triangle::Edge::Name::wu;
ns.wu.edge.a = ns.wu.triangle->w_idx();
ns.wu.edge.b = ns.wu.triangle->u_idx();
ns.wu.edge.c = ns.wu.triangle->v_idx();
}
neighbors.insert(triangles[i], ns);
}
}
f->glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
qCDebug(log_timing) << "Building map:" << formatTimeMeasurement(subTimer.elapsed());
f->glDeleteBuffers(1, &vb_handle);
f->glDeleteBuffers(1, &ib_handle);
f->glDeleteBuffers(1, &output_handle);
qCDebug(log_timing) << "buildNeighborsMap_gpu done:" << formatTimeMeasurement(timer.elapsed());
}
void Subdivision::precomputeEdgeTable(Subdivision::Tables &tables, QVector<Triangle> &triangles, QMap<Triangle, Triangle::Neighbors> &neighbors, unsigned int offset) {
//compute edge table
//Format: first two entries: edge vertices. last two entries: distant vertices.
......
......@@ -51,12 +51,14 @@ private:
QString formatTimeMeasurement(int time);
QOpenGLFunctions_4_3_Core *f;
QOpenGLShaderProgram *neighborsShader;
QOpenGLShaderProgram *copyShader;
QOpenGLShaderProgram *edgeShader;
QOpenGLShaderProgram *vertexShader;
QOpenGLShaderProgram *initComputeShaderProgram(QString &source);
Tables precomputeTables(Input input);
void buildNeighborsMap(QVector<Vertex> &vb, QVector<Triangle> &triangles, QMap<Triangle, Triangle::Neighbors> &neighbors);
void precomputeEdgeTable(Subdivision::Tables &tables, QVector<Triangle> &triangles, QMap<Triangle, Triangle::Neighbors> &neighbors, unsigned int offset);
void precomputeVertexTable(Subdivision::Tables &tables, Input &input, QMap<unsigned int, unsigned int> &modified_vertices);
void updateIndexBuffer(QVector<unsigned int> &index_buffer, QMap<unsigned int, unsigned int> map);
......
......@@ -225,22 +225,6 @@ void insert_neighbor(QMap<Triangle, Triangle::Neighbors> &neighbors, const Trian
neighbors.insert(triangle_a, ns);
}
void buildNeighborsMap(QVector<Triangle> &triangles, QMap<Triangle, Triangle::Neighbors> &neighbors) {
Triangle::Edge edge_a, edge_b;
for (int i = 0; i < triangles.length(); i++){
Triangle *triangle_a = &triangles[i];
for (int j = i + 1; j < triangles.length(); j++){
Triangle *triangle_b = &triangles[j];
if (triangle_a->get_shared_edge(*triangle_b, edge_a, edge_b)) {
insert_neighbor(neighbors, *triangle_a, edge_a, triangle_b, edge_b);
insert_neighbor(neighbors, *triangle_b, edge_b, triangle_a, edge_a);
}
}
}
}
QDebug operator<<(QDebug d, const Triangle &triangle) {
QDebugStateSaver saver(d);
d.nospace() << "Triangle(" << triangle.u_idx() << ", " << triangle.v_idx() << ", " << triangle.w_idx() << "; " << triangle.u().pos << ", " << triangle.v().pos << ", " << triangle.w().pos << ")";
......
......@@ -73,7 +73,6 @@ class Triangle {
Triangle::Edge::Name rotate_edge_name(Triangle::Edge::Name edge);
void ibToTriangles(QVector<Vertex> *vb, QVector<unsigned int> &ib, QVector<Triangle> &triangles);
void buildNeighborsMap(QVector<Triangle> &triangles, QMap<Triangle, Triangle::Neighbors> &neighbors);
QDebug operator<<(QDebug d, const Triangle &triangle);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment