aboutsummaryrefslogtreecommitdiff
path: root/samples
diff options
context:
space:
mode:
authorWolfgang Draxinger <Wolfgang.Draxinger@draxit.de>2016-04-24 23:33:05 +0200
committerWolfgang Draxinger <Wolfgang.Draxinger@draxit.de>2016-04-24 23:33:05 +0200
commita00fb682a7e3552ab4f5ee0a161d0e21d17d6a26 (patch)
tree4c25244223bde246c97cce0335da0dad4e353959 /samples
parent1e387fc8eee4925616967edd26de0ee416dbce3f (diff)
downloadcodesamples-a00fb682a7e3552ab4f5ee0a161d0e21d17d6a26.tar.gz
codesamples-a00fb682a7e3552ab4f5ee0a161d0e21d17d6a26.tar.bz2
computeshader
Diffstat (limited to 'samples')
-rw-r--r--samples/OpenGL/compute_shader/.syntastic_c_config1
-rw-r--r--samples/OpenGL/compute_shader/Makefile19
-rw-r--r--samples/OpenGL/compute_shader/main.c275
-rw-r--r--samples/OpenGL/compute_shader/mvp.vs.glsl12
-rw-r--r--samples/OpenGL/compute_shader/phong.fs.glsl0
-rw-r--r--samples/OpenGL/compute_shader/phong.vs.glsl0
-rw-r--r--samples/OpenGL/compute_shader/positiongen.c51
-rw-r--r--samples/OpenGL/compute_shader/positiongen.glsl24
-rw-r--r--samples/OpenGL/compute_shader/positiongen.h15
-rw-r--r--samples/OpenGL/compute_shader/solid.c64
-rw-r--r--samples/OpenGL/compute_shader/solid.fs.glsl9
-rw-r--r--samples/OpenGL/compute_shader/solid.h17
-rw-r--r--samples/OpenGL/compute_shader/stats.c25
-rw-r--r--samples/OpenGL/compute_shader/stats.h35
14 files changed, 547 insertions, 0 deletions
diff --git a/samples/OpenGL/compute_shader/.syntastic_c_config b/samples/OpenGL/compute_shader/.syntastic_c_config
new file mode 100644
index 0000000..8d5751c
--- /dev/null
+++ b/samples/OpenGL/compute_shader/.syntastic_c_config
@@ -0,0 +1 @@
+-I../../../extra
diff --git a/samples/OpenGL/compute_shader/Makefile b/samples/OpenGL/compute_shader/Makefile
new file mode 100644
index 0000000..f6191f1
--- /dev/null
+++ b/samples/OpenGL/compute_shader/Makefile
@@ -0,0 +1,19 @@
+OBJS = main.o positiongen.o solid.o stats.o shaderloader.o debuggl.o
+CFLAGS = -std=c99 -I../../../extra
+LDLIBS = -lGL -lGLEW -lglut -lm
+
+.PHONY: all clean
+
+all: computeshader
+
+clean:
+ -rm -f $(OBJS) computeshader
+
+computeshader: $(OBJS)
+ $(CC) $(LDFLAGS) -o computeshader $(OBJS) $(LOADLIBES) $(LDLIBS)
+
+shaderloader.o: ../../../extra/shaderloader/shaderloader.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+debuggl.o: ../../../extra/debuggl/debuggl.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
diff --git a/samples/OpenGL/compute_shader/main.c b/samples/OpenGL/compute_shader/main.c
new file mode 100644
index 0000000..c6acdc3
--- /dev/null
+++ b/samples/OpenGL/compute_shader/main.c
@@ -0,0 +1,275 @@
+#include <GL/glew.h>
+#include <GL/glut.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "debuggl/debuggl.h"
+#include "linmath.h/linmath.h"
+
+#include "positiongen.h"
+#include "solid.h"
+#include "stats.h"
+
+#define HAS_ARCBALL 0
+
+static struct {
+ int width;
+ int height;
+ float aspect;
+} window;
+
+static struct {
+ GLuint vbo;
+ GLuint vao;
+ int grid[2];
+} vertexbuffer;
+
+static GLuint timerquery;
+
+#if HAS_ARCBALL
+#define MAT4X4_IDENTITY {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}
+static struct dragging {
+ bool left;
+ vec2 v;
+} pointer_dragging;
+static mat4x4 view = MAT4X4_IDENTITY;
+static mat4x4 arcball = MAT4X4_IDENTITY;
+#endif
+
+static struct stats_running drawtime_stats = STATS_RUNNING_INIT;
+
+static
+int create_vertexbuffer(int rows, int cols)
+{
+ size_t const dim = 4;
+
+ debuggl_check( glGenVertexArrays(1, &vertexbuffer.vao) );
+ debuggl_check( glBindVertexArray(vertexbuffer.vao) );
+
+ debuggl_check( glGenBuffers(1, &vertexbuffer.vbo) );
+ debuggl_check( glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer.vbo) );
+
+ debuggl_check( glBufferStorage(GL_ARRAY_BUFFER,
+ sizeof(GLfloat)*dim * rows * cols,
+ NULL, 0 ) );
+
+ debuggl_check( glEnableVertexAttribArray(0) );
+ debuggl_check( glVertexAttribPointer(0, dim, GL_FLOAT, GL_FALSE, 0, 0) );
+
+ vertexbuffer.grid[0] = rows;
+ vertexbuffer.grid[1] = cols;
+
+ debuggl_check( glBindBuffer(GL_ARRAY_BUFFER, 0) );
+ debuggl_check( glBindVertexArray(0) );
+
+ return 0;
+}
+
+static
+int load_shaders(void)
+{
+ int rc;
+ (void)(0
+ || (rc= positiongen_load() )
+ || (rc= solid_load() )
+ );
+ return rc;
+}
+
+static
+int create_resources(void)
+{
+ int rc;
+ (void)(0
+ || (rc= create_vertexbuffer(1024, 1024) )
+ || (rc= load_shaders() )
+ );
+
+ if( !rc ) {
+ debuggl_check( glGenQueries(1, &timerquery) );
+ }
+
+ return rc;
+}
+
+static
+void keyboard(unsigned char key, int x, int y)
+{
+ switch(key) {
+ case 'r':
+ case 'R':
+ load_shaders();
+ glutPostRedisplay();
+ break;
+ }
+}
+
+#if HAS_ARCBALL
+static
+void pointer_button(int button, int state, int x, int y)
+{
+ if( GLUT_LEFT_BUTTON == button ) {
+ if( GLUT_UP == state ) {
+ pointer_dragging.left = false;
+
+ mat4x4_mul(view, arcball, view);
+ mat4x4_orthonormalize(view, view);
+ mat4x4_identity(arcball);
+ }
+ else {
+ pointer_dragging.left = true;
+
+ pointer_dragging.v[0] = 2.f * (float)x / window.width - 1.f;
+ pointer_dragging.v[1] = -2.f * (float)y / window.height + 1.f;
+ }
+ }
+}
+
+static
+void pointer_drag_motion(int x, int y)
+{
+ if( pointer_dragging.left ) {
+ vec2 motion_v = {
+ 2.f * (float)x / window.width - 1.f,
+ -2.f * (float)y / window.height + 1.f
+ };
+
+ mat4x4_identity(arcball);
+ mat4x4_arcball(arcball, arcball,
+ pointer_dragging.v,
+ motion_v,
+ 1 );
+ glutPostRedisplay();
+ }
+}
+#endif
+
+static
+void reshape(int w, int h)
+{
+ window.width = w;
+ window.height = h;
+ window.aspect = (float)w / (float)h;
+
+ stats_running_reset(&drawtime_stats);
+
+ glutPostRedisplay();
+}
+
+static
+void display(void)
+{
+ mat4x4 proj;
+ mat4x4_identity(proj);
+
+ float const fov = 0.5;
+ mat4x4_frustum(proj,
+ -window.aspect*fov,
+ window.aspect*fov,
+ -fov,
+ fov, 1, 5);
+
+ mat4x4 mv;
+ mat4x4_identity(mv);
+ mat4x4_translate(mv, 0, 0, -3);
+#if HAS_ARCBALL
+ mat4x4_mul(mv, mv, arcball);
+ mat4x4_mul(mv, mv, view);
+#endif
+
+ glViewport(0,0,window.width,window.height);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ positiongen_launch(
+ glutGet(GLUT_ELAPSED_TIME)*0.001,
+ vertexbuffer.vbo,
+ vertexbuffer.grid[0],
+ vertexbuffer.grid[1] );
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ float const white[4] = {1., 1., 1., 0.01};
+ glBeginQuery(GL_TIME_ELAPSED, timerquery);
+ solid_draw(
+ GL_POINTS,
+ vertexbuffer.vao,
+ vertexbuffer.grid[0] * vertexbuffer.grid[1],
+ white,
+ mv[0], proj[0]);
+ glEndQuery(GL_TIME_ELAPSED);
+
+ glutSwapBuffers();
+
+ GLuint timeresult;
+ glGetQueryObjectuiv(timerquery, GL_QUERY_RESULT, &timeresult);
+ stats_running_push(&drawtime_stats, timeresult*0.001);
+}
+
+enum {
+ win_width_inc = 64, win_height_inc = 64,
+ win_width_max = 1024, win_height_max = 1024
+};
+static int win_width = win_width_inc, win_height = win_height_inc;
+
+static
+void idle(void)
+{
+ if( 499 < stats_running_N(&drawtime_stats) ) {
+ printf("%4d x %4d: ( %7.1f +/- %7.1f )us\n",
+ win_width, win_height,
+ stats_running_mean(&drawtime_stats),
+ sqrt(stats_running_variance(&drawtime_stats)) );
+
+ win_width += win_width_inc;
+ if( win_width_max < win_width ) {
+ win_height += win_height_inc;
+ if( win_height_max < win_height ) {
+ exit(0);
+ }
+ win_width = win_width_inc;
+ }
+ glutReshapeWindow(win_width, win_height);
+ }
+ glutPostRedisplay();
+}
+
+static
+void gldebugcallback(
+ GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar *message,
+ const void *userParam)
+{
+ fprintf(stderr, "(GL) %s\n", message);
+}
+
+int main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+
+ glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+ glutInitWindowPosition(0,0);
+ glutInitWindowSize(win_width, win_height);
+ glutCreateWindow("Compute Shader");
+ if( GLEW_OK != glewInit() ) { return 1; }
+
+ glDebugMessageCallback((GLDEBUGPROC)gldebugcallback, NULL);
+ glEnable(GL_DEBUG_OUTPUT);
+
+ if( create_resources() ) { return 2; }
+
+ glutReshapeFunc(reshape);
+ glutKeyboardFunc(keyboard);
+#if HAS_ARCBALL
+ glutMouseFunc(pointer_button);
+ glutMotionFunc(pointer_drag_motion);
+#endif
+ glutDisplayFunc(display);
+ glutIdleFunc(idle);
+
+ glutMainLoop();
+ return 0;
+}
diff --git a/samples/OpenGL/compute_shader/mvp.vs.glsl b/samples/OpenGL/compute_shader/mvp.vs.glsl
new file mode 100644
index 0000000..4c4d062
--- /dev/null
+++ b/samples/OpenGL/compute_shader/mvp.vs.glsl
@@ -0,0 +1,12 @@
+#version 430
+
+layout(location = 0) in vec4 a_position;
+
+uniform mat4 u_modelview;
+uniform mat4 u_projection;
+
+void main()
+{
+ const mat4 mvp = u_projection * u_modelview;
+ gl_Position = mvp * a_position;
+}
diff --git a/samples/OpenGL/compute_shader/phong.fs.glsl b/samples/OpenGL/compute_shader/phong.fs.glsl
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samples/OpenGL/compute_shader/phong.fs.glsl
diff --git a/samples/OpenGL/compute_shader/phong.vs.glsl b/samples/OpenGL/compute_shader/phong.vs.glsl
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/samples/OpenGL/compute_shader/phong.vs.glsl
diff --git a/samples/OpenGL/compute_shader/positiongen.c b/samples/OpenGL/compute_shader/positiongen.c
new file mode 100644
index 0000000..3349ff6
--- /dev/null
+++ b/samples/OpenGL/compute_shader/positiongen.c
@@ -0,0 +1,51 @@
+#include <GL/glew.h>
+#include "positiongen.h"
+
+#include "shaderloader/shaderloader.h"
+#include "debuggl/debuggl.h"
+
+#include <stdio.h>
+
+static struct {
+ GLuint program;
+ GLint w_output;
+ GLint u_time;
+} positiongen;
+
+int positiongen_load(void)
+{
+ debuggl_check( "pre positiongen_load check" );
+
+ char const * const paths[] = { "positiongen.glsl", 0 };
+ shader_program_sources const sources[] = { {GL_COMPUTE_SHADER, paths}, {0,0} };
+
+ if( positiongen.program ) {
+ debuggl_check( glDeleteProgram(positiongen.program) );
+ positiongen.program = 0;
+ }
+
+ positiongen.program = shader_program_load_from_files(sources);
+ if( !positiongen.program ) {
+ fprintf(stderr, "%s failed\n", __func__);
+ return -2;
+ }
+
+ debuggl_check( positiongen.w_output = glGetProgramResourceIndex(positiongen.program, GL_SHADER_STORAGE_BLOCK, "w_output") );
+ debuggl_check( positiongen.u_time = glGetProgramResourceLocation(positiongen.program, GL_UNIFORM, "u_time") );
+
+ return 0;
+}
+
+int positiongen_launch(
+ float t,
+ GLuint vbo,
+ int width,
+ int height )
+{
+ debuggl_check( glUseProgram(positiongen.program) );
+ debuggl_check( glUniform1f(positiongen.u_time, t) );
+ debuggl_check( glBindBufferBase(GL_SHADER_STORAGE_BUFFER, positiongen.w_output, vbo) );
+ debuggl_check( glDispatchCompute(width/16, height/16, 1) );
+ debuggl_check( glBindBufferBase(GL_SHADER_STORAGE_BUFFER, positiongen.w_output, 0) );
+ debuggl_check( glUseProgram(0) );
+}
diff --git a/samples/OpenGL/compute_shader/positiongen.glsl b/samples/OpenGL/compute_shader/positiongen.glsl
new file mode 100644
index 0000000..99018b6
--- /dev/null
+++ b/samples/OpenGL/compute_shader/positiongen.glsl
@@ -0,0 +1,24 @@
+#version 430
+
+layout( local_size_x = 16, local_size_y = 16 ) in;
+layout(std430) buffer;
+layout(binding = 0) buffer w_output {
+ vec4 data[];
+};
+
+uniform float u_time;
+
+void main()
+{
+ uvec3 GlobalSize = gl_WorkGroupSize * gl_NumWorkGroups;
+ uint GlobalInvocationIndex =
+ GlobalSize.x * GlobalSize.y * gl_GlobalInvocationID.z
+ + GlobalSize.x * gl_GlobalInvocationID.y
+ + gl_GlobalInvocationID.x;
+
+ vec2 p = 2*vec2(gl_GlobalInvocationID.xy)/GlobalSize.xy - 1;
+
+ float z = sin(10.*p.x + u_time) + sin(30.*p.y + 0.1*u_time);
+
+ data[GlobalInvocationIndex] = vec4(p, z*0.25, 1);
+}
diff --git a/samples/OpenGL/compute_shader/positiongen.h b/samples/OpenGL/compute_shader/positiongen.h
new file mode 100644
index 0000000..d1a30cd
--- /dev/null
+++ b/samples/OpenGL/compute_shader/positiongen.h
@@ -0,0 +1,15 @@
+#pragma once
+#ifndef POSITIONGEN_H
+#define POSITIONGEN_H
+
+#include <GL/gl.h>
+
+int positiongen_load(void);
+
+int positiongen_launch(
+ float t,
+ GLuint vbo,
+ int width,
+ int height );
+
+#endif/*POSITIONGEN_H*/
diff --git a/samples/OpenGL/compute_shader/solid.c b/samples/OpenGL/compute_shader/solid.c
new file mode 100644
index 0000000..982e24a
--- /dev/null
+++ b/samples/OpenGL/compute_shader/solid.c
@@ -0,0 +1,64 @@
+#include <GL/glew.h>
+#include "solid.h"
+
+#include "shaderloader/shaderloader.h"
+#include "debuggl/debuggl.h"
+
+#include <stdio.h>
+
+static struct {
+ GLint program;
+ GLint u_modelview;
+ GLint u_projection;
+ GLint u_color;
+} solid;
+
+int solid_load(void)
+{
+ debuggl_check( "pre solid_load check" );
+
+ char const * const paths_vs[] = { "mvp.vs.glsl", 0 };
+ char const * const paths_fs[] = { "solid.fs.glsl", 0 };
+ shader_program_sources const sources[] = {
+ {GL_VERTEX_SHADER, paths_vs},
+ {GL_FRAGMENT_SHADER, paths_fs},
+ {0,0}
+ };
+
+ if( solid.program ) {
+ debuggl_check( glDeleteProgram(solid.program) );
+ solid.program = 0;
+ }
+
+ solid.program = shader_program_load_from_files(sources);
+ if( !solid.program ) {
+ fprintf(stderr, "%s failed\n", __func__);
+ return -2;
+ }
+
+ debuggl_check( solid.u_modelview = glGetProgramResourceLocation(solid.program, GL_UNIFORM, "u_modelview") );
+ debuggl_check( solid.u_projection = glGetProgramResourceLocation(solid.program, GL_UNIFORM, "u_projection") );
+ debuggl_check( solid.u_color = glGetProgramResourceLocation(solid.program, GL_UNIFORM, "u_color") );
+
+ return 0;
+}
+
+int solid_draw(
+ GLenum primitive,
+ GLuint vao,
+ GLsizei count,
+ GLfloat const * const color,
+ GLfloat const * const modelview,
+ GLfloat const * const projection )
+{
+ debuggl_check( (void)"pre solid_draw check" );
+
+ debuggl_check( glBindVertexArray(vao) );
+ debuggl_check( glUseProgram(solid.program) );
+ debuggl_check( glUniform4fv(solid.u_color, 1, color) );
+ debuggl_check( glUniformMatrix4fv(solid.u_modelview, 1, GL_FALSE, modelview) );
+ debuggl_check( glUniformMatrix4fv(solid.u_projection, 1, GL_FALSE, projection) );
+ debuggl_check( glDrawArrays(primitive, 0, count) );
+ debuggl_check( glUseProgram(0) );
+ debuggl_check( glBindVertexArray(0) );
+}
diff --git a/samples/OpenGL/compute_shader/solid.fs.glsl b/samples/OpenGL/compute_shader/solid.fs.glsl
new file mode 100644
index 0000000..397cd33
--- /dev/null
+++ b/samples/OpenGL/compute_shader/solid.fs.glsl
@@ -0,0 +1,9 @@
+#version 430
+
+uniform vec4 u_color;
+out vec4 o_fragcolor;
+
+void main()
+{
+ o_fragcolor = u_color;
+}
diff --git a/samples/OpenGL/compute_shader/solid.h b/samples/OpenGL/compute_shader/solid.h
new file mode 100644
index 0000000..c89aeba
--- /dev/null
+++ b/samples/OpenGL/compute_shader/solid.h
@@ -0,0 +1,17 @@
+#pragma once
+#ifndef SOLID_H
+#define SOLID_H
+
+#include <GL/gl.h>
+
+int solid_load(void);
+
+int solid_draw(
+ GLenum primitive,
+ GLuint vao,
+ GLsizei count,
+ GLfloat const * const color,
+ GLfloat const * const modelview,
+ GLfloat const * const projection );
+
+#endif/*POSITIONGEN_H*/
diff --git a/samples/OpenGL/compute_shader/stats.c b/samples/OpenGL/compute_shader/stats.c
new file mode 100644
index 0000000..1cf7fcb
--- /dev/null
+++ b/samples/OpenGL/compute_shader/stats.c
@@ -0,0 +1,25 @@
+#include "stats.h"
+
+void stats_running_reset(struct stats_running *s)
+{
+ if( s ) {
+ s->n = 0;
+ s->S = NAN;
+ s->m = NAN;
+ }
+}
+
+void stats_running_push(struct stats_running *s, double value)
+{
+ if( s && isfinite(value) ) {
+ double const m_prev = 0 < s->n ? s->m : 0.;
+ double const S_prev = 1 < s->n ? s->S : 0.;
+ unsigned const n = (s->n += 1);
+
+ s->m = m_prev + (value - m_prev) / n;
+ if( 1 < n ) {
+ /* variance is defined only for n > 1 */
+ s->S = S_prev + (value - s->m) * (value - m_prev);
+ }
+ }
+}
diff --git a/samples/OpenGL/compute_shader/stats.h b/samples/OpenGL/compute_shader/stats.h
new file mode 100644
index 0000000..8796161
--- /dev/null
+++ b/samples/OpenGL/compute_shader/stats.h
@@ -0,0 +1,35 @@
+#pragma once
+#ifndef STATS_H
+#define STATS_H
+
+#include <math.h>
+
+struct stats_running {
+ unsigned n;
+ double S;
+ double m;
+};
+#define STATS_RUNNING_INIT {0, NAN, NAN}
+
+void stats_running_reset(struct stats_running *s);
+void stats_running_push(struct stats_running *s, double value);
+
+static inline
+unsigned stats_running_N(struct stats_running const *s)
+{
+ return s ? s->n : 0;
+}
+
+static inline
+double stats_running_mean(struct stats_running const *s)
+{
+ return s && (0 < s->n) ? s->m : NAN;
+}
+
+static inline
+double stats_running_variance(struct stats_running const *s)
+{
+ return s && (1 < s->n) ? s->S/s->n : NAN;
+}
+
+#endif/*STATS_H*/