aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.c289
-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
-rw-r--r--samples/OpenGL/frustum/Makefile3
-rw-r--r--samples/OpenGL/frustum/frustum.c2
-rw-r--r--samples/OpenGL/frustum/screenshot.pngbin0 -> 178509 bytes
-rw-r--r--samples/OpenGL/minimal_glsl/minimal_glsl.c2
-rw-r--r--samples/OpenGL/pocketwatch/pocketwatch.cpp4
-rw-r--r--samples/OpenGL/x11argb_opengl/Makefile2
-rw-r--r--samples/OpenGL/x11argb_opengl/x11argb_opengl.c19
-rw-r--r--samples/OpenGL/x11argb_opengl_glsl/Makefile4
-rw-r--r--samples/OpenGL/x11argb_opengl_glsl/x11argb_opengl_glsl.c38
-rw-r--r--samples/OpenGL/x11xcb_opengl/x11xcb_opengl.c238
-rw-r--r--samples/X11/x11atomicbomb/Makefile3
-rw-r--r--samples/X11/x11atomicbomb/x11atomicbomb.c (renamed from samples/X11/x11atomstuffer/x11atomstuffer.c)3
-rw-r--r--samples/X11/x11atomstuffer/Makefile3
-rw-r--r--samples/X11/xcb_shm_image/Makefile9
-rw-r--r--samples/X11/xcb_shm_image/xcb_shm_image_example.c219
29 files changed, 1081 insertions, 29 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..a519439
--- /dev/null
+++ b/samples/OpenGL/compute_shader/main.c
@@ -0,0 +1,289 @@
+#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);
+}
+
+static
+void glinfodump(void)
+{
+ printf(
+ "OpenGL vendor: %s\n"
+ "OpenGL renderer: %s\n"
+ "OpenGL version: %s\n",
+ " GLSL version: %s\n",
+ glGetString(GL_VENDOR),
+ glGetString(GL_RENDERER),
+ glGetString(GL_VERSION),
+ glGetString(GL_SHADING_LANGUAGE_VERSION) );
+}
+
+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 point overdraw benchmark");
+ 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*/
diff --git a/samples/OpenGL/frustum/Makefile b/samples/OpenGL/frustum/Makefile
index 24968ec..748e852 100644
--- a/samples/OpenGL/frustum/Makefile
+++ b/samples/OpenGL/frustum/Makefile
@@ -1,5 +1,4 @@
-CFLAGS = -std=c99
+CFLAGS = -std=c99 -I../../../extra/linmath.h
frustum: frustum.o
$(CC) -o frustum frustum.o -lGL -lGLU -lglut -lm
-
diff --git a/samples/OpenGL/frustum/frustum.c b/samples/OpenGL/frustum/frustum.c
index 5e70382..5aac21e 100644
--- a/samples/OpenGL/frustum/frustum.c
+++ b/samples/OpenGL/frustum/frustum.c
@@ -11,7 +11,7 @@
#include <GL/glu.h>
#include <GL/glut.h>
-#include "linmath.h"
+#include <linmath.h>
#if defined(GLUT_MULTISAMPLE) && defined(GL_MULTISAMPLE)
#define OPTION_GLUT_MULTISAMPLE GLUT_MULTISAMPLE
diff --git a/samples/OpenGL/frustum/screenshot.png b/samples/OpenGL/frustum/screenshot.png
new file mode 100644
index 0000000..966cc12
--- /dev/null
+++ b/samples/OpenGL/frustum/screenshot.png
Binary files differ
diff --git a/samples/OpenGL/minimal_glsl/minimal_glsl.c b/samples/OpenGL/minimal_glsl/minimal_glsl.c
index 72ba3ff..f8599cb 100644
--- a/samples/OpenGL/minimal_glsl/minimal_glsl.c
+++ b/samples/OpenGL/minimal_glsl/minimal_glsl.c
@@ -1,7 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <GL/glew.h>
-#include <GL/glfw.h>
+#include <GLFW/glfw3.h>
static void pushModelview()
{
diff --git a/samples/OpenGL/pocketwatch/pocketwatch.cpp b/samples/OpenGL/pocketwatch/pocketwatch.cpp
index e04ad0e..f6b49b0 100644
--- a/samples/OpenGL/pocketwatch/pocketwatch.cpp
+++ b/samples/OpenGL/pocketwatch/pocketwatch.cpp
@@ -14,7 +14,7 @@ void idle();
int main(int argc, char **argv)
{
glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
+ glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH|GLUT_MULTISAMPLE);
glutCreateWindow("PocketWatch");
glutDisplayFunc(display);
@@ -37,6 +37,8 @@ void init()
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
+
+ glEnable(GL_MULTISAMPLE);
}
float light_position[]={-0.5,0.5,1,0};
diff --git a/samples/OpenGL/x11argb_opengl/Makefile b/samples/OpenGL/x11argb_opengl/Makefile
index abafd5c..5b35c1b 100644
--- a/samples/OpenGL/x11argb_opengl/Makefile
+++ b/samples/OpenGL/x11argb_opengl/Makefile
@@ -1,3 +1,3 @@
x11argb_opengl: x11argb_opengl.c Makefile
- $(CC) -std=c99 -g3 -o x11argb_opengl -DUSE_GLX_CREATE_CONTEXT_ATTRIB=1 x11argb_opengl.c -lX11 -lXrender -lGL -lm
+ $(CC) -std=c99 -g3 -o x11argb_opengl -DUSE_GLX_CREATE_CONTEXT_ATTRIB=1 -DUSE_GLX_CREATE_WINDOW=1 x11argb_opengl.c -lX11 -lXrender -lGL -lm
diff --git a/samples/OpenGL/x11argb_opengl/x11argb_opengl.c b/samples/OpenGL/x11argb_opengl/x11argb_opengl.c
index 092c202..fb1b54c 100644
--- a/samples/OpenGL/x11argb_opengl/x11argb_opengl.c
+++ b/samples/OpenGL/x11argb_opengl/x11argb_opengl.c
@@ -160,6 +160,7 @@ static void createTheWindow()
if(pict_format->direct.alphaMask > 0) {
break;
}
+ XFree(visual);
}
if(!fbconfig) {
@@ -210,6 +211,7 @@ static void createTheWindow()
}
#if USE_GLX_CREATE_WINDOW
+ fputs("glXCreateWindow ", stderr);
int glXattr[] = { None };
glX_window_handle = glXCreateWindow(Xdisplay, fbconfig, window_handle, glXattr);
if( !glX_window_handle ) {
@@ -252,7 +254,7 @@ static void createTheWindow()
static int ctxErrorHandler( Display *dpy, XErrorEvent *ev )
{
- fputs("Error at context creation", stderr);
+ fputs("Error at context creation\n", stderr);
return 0;
}
@@ -269,12 +271,12 @@ static void createTheRenderContext()
render_context = NULL;
if( isExtensionSupported( glXQueryExtensionsString(Xdisplay, DefaultScreen(Xdisplay)), "GLX_ARB_create_context" ) ) {
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
- glXCreateContextAttribsARBProc glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
+ glXCreateContextAttribsARBProc glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB("glXCreateContextAttribsARB" );
if( glXCreateContextAttribsARB ) {
int context_attribs[] =
{
- GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
- GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 1,
//GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
@@ -285,17 +287,16 @@ static void createTheRenderContext()
XSync( Xdisplay, False );
XSetErrorHandler( oldHandler );
-
- fputs("glXCreateContextAttribsARB failed", stderr);
} else {
- fputs("glXCreateContextAttribsARB could not be retrieved", stderr);
+ fputs("glXCreateContextAttribsARB could not be retrieved\n", stderr);
}
} else {
- fputs("glXCreateContextAttribsARB not supported", stderr);
+ fputs("glXCreateContextAttribsARB not supported\n", stderr);
}
if(!render_context)
{
+ fputs("using fallback\n", stderr);
#else
{
#endif
@@ -471,7 +472,7 @@ static void redrawTheWindow()
glXSwapBuffers(Xdisplay, glX_window_handle);
clock_gettime(CLOCK_MONOTONIC_RAW, &Tb);
- fprintf(stderr, "glXSwapBuffers returned after %f ms\n", 1e3*((double)Tb.tv_sec + 1e-6*(double)Tb.tv_nsec) - 1e3*((double)Ta.tv_sec + 1e-6*(double)Ta.tv_nsec));
+ // fprintf(stderr, "glXSwapBuffers returned after %f ms\n", 1e3*((double)Tb.tv_sec + 1e-6*(double)Tb.tv_nsec) - 1e3*((double)Ta.tv_sec + 1e-6*(double)Ta.tv_nsec));
}
int main(int argc, char *argv[])
diff --git a/samples/OpenGL/x11argb_opengl_glsl/Makefile b/samples/OpenGL/x11argb_opengl_glsl/Makefile
index 62e3496..b5e461a 100644
--- a/samples/OpenGL/x11argb_opengl_glsl/Makefile
+++ b/samples/OpenGL/x11argb_opengl_glsl/Makefile
@@ -3,8 +3,8 @@
all: x11argb_opengl_glsl x11argb_opengl_glsl3
x11argb_opengl_glsl: x11argb_opengl_glsl.c Makefile
- cc -std=c99 -g3 -o x11argb_opengl_glsl x11argb_opengl_glsl.c -lX11 -lXrender -lGLEW -lm
+ cc -std=c99 -g3 -o x11argb_opengl_glsl x11argb_opengl_glsl.c -lX11 -lXrender -lGL -lGLEW -lm
x11argb_opengl_glsl3: x11argb_opengl_glsl.c Makefile
- cc -std=c99 -g3 -o x11argb_opengl_glsl3 -D USE_GLX_CREATE_CONTEXT_ATTRIB x11argb_opengl_glsl.c -lX11 -lXrender -lGLEW -lm
+ cc -std=c99 -g3 -o x11argb_opengl_glsl3 -D USE_GLX_CREATE_CONTEXT_ATTRIB x11argb_opengl_glsl.c -lX11 -lXrender -lGL -lGLEW -lm
diff --git a/samples/OpenGL/x11argb_opengl_glsl/x11argb_opengl_glsl.c b/samples/OpenGL/x11argb_opengl_glsl/x11argb_opengl_glsl.c
index 7aae5a8..a5b6180 100644
--- a/samples/OpenGL/x11argb_opengl_glsl/x11argb_opengl_glsl.c
+++ b/samples/OpenGL/x11argb_opengl_glsl/x11argb_opengl_glsl.c
@@ -26,6 +26,7 @@
#define _GNU_SOURCE
+#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -41,8 +42,8 @@
#include <X11/extensions/Xrender.h>
#include <X11/Xutil.h>
-#define USE_CHOOSE_FBCONFIG
-#define USE_GLX_CREATE_WINDOW
+#define USE_GLX_CREATE_WINDOW 1
+#define USE_DOUBLEBUFFER 1
static const GLchar *vertex_shader_source =
"#version 120\n"
@@ -182,7 +183,11 @@ static int width, height;
static int VisData[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+#if USE_DOUBLEBUFFER
GLX_DOUBLEBUFFER, True,
+#else
+GLX_DOUBLEBUFFER, False,
+#endif
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
@@ -296,7 +301,7 @@ static void createTheWindow()
fatalError("Couldn't create the window\n");
}
-#ifdef USE_GLX_CREATE_WINDOW
+#if USE_GLX_CREATE_WINDOW
int glXattr[] = { None };
glX_window_handle = glXCreateWindow(Xdisplay, fbconfig, window_handle, glXattr);
if( !glX_window_handle ) {
@@ -365,7 +370,7 @@ static void createTheRenderContext()
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
- //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+ GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
@@ -578,8 +583,12 @@ static void redrawTheWindow(double T)
struct timespec Ta, Tb;
+#if USE_DOUBLEBUFFER
glXSwapBuffers(Xdisplay, glX_window_handle);
- glXWaitGL();
+#else
+ glFlush();
+ usleep(10000);
+#endif
}
static double getftime(void) {
@@ -608,8 +617,23 @@ int main(int argc, char *argv[])
if( !init_resources() )
return -1;
- while (updateTheMessageQueue()) {
- redrawTheWindow(getftime());
+ int n_dT_accum = 0;
+ float dT_accum = 0;
+ while( updateTheMessageQueue() ) {
+ float const dT = getftime();
+ redrawTheWindow(dT);
+
+ dT_accum += dT;
+ ++n_dT_accum;
+
+ if( 100 < n_dT_accum ) {
+ fprintf(stderr, "%d frames in %fs (~%fFPS)\n",
+ n_dT_accum,
+ dT_accum,
+ (float)n_dT_accum / dT_accum);
+ dT_accum = 0.f;
+ n_dT_accum = 0;
+ }
}
return 0;
diff --git a/samples/OpenGL/x11xcb_opengl/x11xcb_opengl.c b/samples/OpenGL/x11xcb_opengl/x11xcb_opengl.c
new file mode 100644
index 0000000..e1fc3c3
--- /dev/null
+++ b/samples/OpenGL/x11xcb_opengl/x11xcb_opengl.c
@@ -0,0 +1,238 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+
+/*
+If you get linking errors when using C++, you need
+to add extern "C" here or in X11-xcb.h, unless
+this bug is already fixed in your version:
+http://bugs.freedesktop.org/show_bug.cgi?id=22252
+*/
+#include <X11/Xlib-xcb.h> /* for XGetXCBConnection, link with libX11-xcb */
+
+#include <xcb/xcb.h>
+
+#include <GL/glx.h>
+#include <GL/gl.h>
+
+static
+void draw()
+{
+ glClearColor(0.2, 0.4, 0.9, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+static
+int main_loop(
+ Display *display,
+ xcb_connection_t *connection,
+ xcb_window_t window,
+ GLXDrawable drawable )
+{
+ int running = 1;
+ while(running) {
+ /* Wait for event */
+ xcb_generic_event_t *event = xcb_wait_for_event(connection);
+ if( !event ) {
+ fprintf(stderr, "i/o error in xcb_wait_for_event");
+ return -1;
+ }
+
+ switch(event->response_type & ~0x80) {
+ case XCB_KEY_PRESS:
+ /* Quit on key press */
+ running = 0;
+ break;
+
+ case XCB_EXPOSE:
+ /* Handle expose event, draw and swap buffers */
+ draw();
+ glXSwapBuffers(display, drawable);
+ break;
+
+ default:
+ break;
+ }
+
+ free(event);
+ }
+
+ return 0;
+}
+
+static
+int setup_and_run(
+ Display* display,
+ xcb_connection_t *connection,
+ int default_screen,
+ xcb_screen_t *screen )
+{
+ xcb_generic_error_t *error;
+
+ /* Query framebuffer configurations */
+ int num_fb_configs = 0;
+ GLXFBConfig * const fb_configs = glXGetFBConfigs(display, default_screen, &num_fb_configs);
+ if( !fb_configs || !num_fb_configs ){
+ fprintf(stderr, "glXGetFBConfigs failed\n");
+ return -1;
+ }
+
+ GLXFBConfig fb_config;
+ int visualID = 0;
+ for(int i = 0; !visualID && i < num_fb_configs; ++i) {
+ /* Select first framebuffer config with a valid visual and query visualID */
+ fb_config = fb_configs[i];
+ XVisualInfo * const visual = glXGetVisualFromFBConfig(display, fb_config);
+ if( !visual ) { continue; }
+ visualID = visual->visualid;
+ }
+ if( !visualID ) {
+ return -1;
+ }
+
+ /* Create OpenGL context */
+ GLXContext const context = glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True);
+ if( !context ) {
+ fprintf(stderr, "glXCreateNewContext failed\n");
+ return -1;
+ }
+
+ /* Create XID's for colormap and window */
+ xcb_colormap_t colormap = xcb_generate_id(connection);
+ xcb_window_t window = xcb_generate_id(connection);
+
+ /* Create colormap */
+ if((error = xcb_request_check(connection, xcb_create_colormap_checked(
+ connection,
+ XCB_COLORMAP_ALLOC_NONE,
+ colormap,
+ screen->root,
+ visualID)
+ )
+ )){
+ fprintf(stderr, "error creating colormap: %d\n", error->error_code);
+ free(error);
+ return -1;
+ }
+
+ /* Create window */
+ uint32_t const eventmask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS;
+ uint32_t const valuelist[] = { eventmask, colormap };
+ uint32_t const valuemask = XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
+
+ if((error= xcb_request_check(connection, xcb_create_window_checked(
+ connection,
+ XCB_COPY_FROM_PARENT,
+ window,
+ screen->root,
+ 0, 0,
+ 150, 150,
+ 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ visualID,
+ valuemask,
+ valuelist)
+ )
+ )){
+ fprintf(stderr, "error creating window: %d\n", error->error_code);
+ return -1;
+ }
+
+ // NOTE: window must be mapped before glXMakeContextCurrent
+ if((error= xcb_request_check(connection, xcb_map_window(connection, window)) )) {
+ fprintf(stderr, "error mapping window");
+ return -1;
+ }
+
+ /* Create GLX Window */
+ GLXDrawable drawable = 0;
+
+ GLXWindow glxwindow = glXCreateWindow(display, fb_config, window, 0);
+ if( !window ) {
+ xcb_destroy_window(connection, window);
+ glXDestroyContext(display, context);
+
+ fprintf(stderr, "glXDestroyContext failed\n");
+ return -1;
+ }
+
+ drawable = glxwindow;
+
+ /* make OpenGL context current */
+ if( !glXMakeContextCurrent(display, drawable, drawable, context) ) {
+ xcb_destroy_window(connection, window);
+ glXDestroyContext(display, context);
+
+ fprintf(stderr, "glXMakeContextCurrent failed\n");
+ return -1;
+ }
+
+ /* run main loop */
+ int retval = main_loop(display, connection, window, drawable);
+
+ /* Cleanup */
+ glXDestroyWindow(display, glxwindow);
+ xcb_destroy_window(connection, window);
+ glXDestroyContext(display, context);
+
+ return retval;
+}
+
+static
+void screen_from_Xlib_Display(
+ Display * const display,
+ xcb_connection_t *connection,
+ int * const out_screen_num,
+ xcb_screen_t ** const out_screen)
+{
+ xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
+ int screen_num = DefaultScreen(display);
+ while( screen_iter.rem && screen_num > 0 ) {
+ xcb_screen_next(&screen_iter);
+ --screen_num;
+ }
+ *out_screen_num = screen_num;
+ *out_screen = screen_iter.data;
+}
+
+int main(int argc, char* argv[])
+{
+ Display *display;
+
+ /* Open Xlib Display */
+ display = XOpenDisplay(0);
+ if( !display ) {
+ fprintf(stderr, "Can't open display\n");
+ return -1;
+ }
+
+
+ /* Get the XCB connection from the display */
+ xcb_connection_t *connection = XGetXCBConnection(display);
+ if( !connection ) {
+ XCloseDisplay(display);
+ fprintf(stderr, "Can't get xcb connection from display\n");
+ return -1;
+ }
+
+ /* Acquire event queue ownership */
+ XSetEventQueueOwner(display, XCBOwnsEventQueue);
+
+ /* Find XCB screen */
+ int screen_num;
+ xcb_screen_t *screen = 0;
+ screen_from_Xlib_Display(display, connection, &screen_num, &screen);
+ if( !screen ) {
+ return -1;
+ }
+
+ /* Initialize window and OpenGL context, run main loop and deinitialize */
+ int retval = setup_and_run(display, connection, screen_num, screen);
+
+ /* Cleanup */
+ XCloseDisplay(display);
+
+ return retval;
+}
diff --git a/samples/X11/x11atomicbomb/Makefile b/samples/X11/x11atomicbomb/Makefile
new file mode 100644
index 0000000..bece120
--- /dev/null
+++ b/samples/X11/x11atomicbomb/Makefile
@@ -0,0 +1,3 @@
+x11atomicbomb: x11atomicbomb.c
+ $(CC) -o x11atomicbomb x11atomicbomb.c -lX11
+
diff --git a/samples/X11/x11atomstuffer/x11atomstuffer.c b/samples/X11/x11atomicbomb/x11atomicbomb.c
index dfa86de..2dadc1a 100644
--- a/samples/X11/x11atomstuffer/x11atomstuffer.c
+++ b/samples/X11/x11atomicbomb/x11atomicbomb.c
@@ -1,5 +1,5 @@
/*------------------------------------------------------------------------
- * What happens if you stuff the X11 server with large and large amounts
+ * What happens if you bomb the X11 server with large and large amounts
* of atoms? When does it run out of memory? How is its performance
* impaired by this? This is a little program to experimenting with
* torturing the X11 server by overfeeding it with atoms.
@@ -70,4 +70,3 @@ int main(int argc, char *argv[])
return 0;
}
-
diff --git a/samples/X11/x11atomstuffer/Makefile b/samples/X11/x11atomstuffer/Makefile
deleted file mode 100644
index cf1c234..0000000
--- a/samples/X11/x11atomstuffer/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-x11atomstuffer: x11atomstuffer.c
- $(CC) -o x11atomstuffer x11atomstuffer.c -lX11
-
diff --git a/samples/X11/xcb_shm_image/Makefile b/samples/X11/xcb_shm_image/Makefile
new file mode 100644
index 0000000..963a04b
--- /dev/null
+++ b/samples/X11/xcb_shm_image/Makefile
@@ -0,0 +1,9 @@
+.PHONY: all clean
+
+all: xcb_shm_image_example
+
+clean:
+ - rm xcb_shm_image_example xcb_shm_image_example.o
+
+xcb_shm_image_example: LDFLAGS += -lxcb -lxcb-image -lxcb-shm
+xcb_shm_image_example: xcb_shm_image_example.o
diff --git a/samples/X11/xcb_shm_image/xcb_shm_image_example.c b/samples/X11/xcb_shm_image/xcb_shm_image_example.c
new file mode 100644
index 0000000..4f87e76
--- /dev/null
+++ b/samples/X11/xcb_shm_image/xcb_shm_image_example.c
@@ -0,0 +1,219 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <xcb/xcb.h>
+#include <xcb/shm.h>
+#include <xcb/xcb_image.h>
+
+#if __ORDER_LITTLE_ENDIAN == __BYTE_ORDER__
+# define NATIVE_XCB_IMAGE_ORDER XCB_IMAGE_ORDER_LSB_FIRST
+#else
+# define NATIVE_XCB_IMAGE_ORDER XCB_IMAGE_ORDER_MSB_FIRST
+#endif
+
+enum {
+ IMAGE_WIDTH = 512,
+ IMAGE_HEIGHT = 512,
+ IMAGE_DEPTH = 24,
+};
+
+static xcb_format_t const *query_xcb_format_for_depth(
+ xcb_connection_t *const connection,
+ unsigned depth )
+{
+ xcb_setup_t const *const setup = xcb_get_setup(connection);
+ xcb_format_iterator_t it;
+ for( it = xcb_setup_pixmap_formats_iterator(setup)
+ ; it.rem
+ ; xcb_format_next(&it)
+ ){
+ xcb_format_t const *const format = it.data;
+ if( format->depth == depth ){
+ return format;
+ }
+ }
+ return NULL;
+}
+
+typedef struct shm_xcb_image_t {
+ xcb_connection_t *connection;
+ xcb_image_t *image;
+ xcb_shm_seg_t shm_seg;
+ int shm_id;
+} shm_xcb_image_t;
+
+static shm_xcb_image_t *shm_xcb_image_create(
+ xcb_connection_t *const connection,
+ unsigned const width,
+ unsigned const height,
+ unsigned const depth )
+{
+ xcb_generic_error_t *error = NULL;
+
+ shm_xcb_image_t *shmimg = calloc(1, sizeof(*shmimg));
+ if( !shmimg ){ goto fail; }
+ shmimg->connection = connection;
+
+ xcb_format_t const *const format = query_xcb_format_for_depth(connection, depth);
+ shmimg->image = xcb_image_create(
+ width, height,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ format->scanline_pad,
+ format->depth, format->bits_per_pixel, 0,
+ NATIVE_XCB_IMAGE_ORDER,
+ XCB_IMAGE_ORDER_MSB_FIRST,
+ NULL, ~0, 0);
+ if( !shmimg->image ){
+ fprintf(stderr, "could not create X11 image structure\n");
+ }
+ size_t const image_segment_size = shmimg->image->stride * shmimg->image->height;
+
+ shmimg->shm_id = shmget(IPC_PRIVATE, image_segment_size, IPC_CREAT | 0600);
+ if( 0 > shmimg->shm_id ){ goto fail; }
+
+ shmimg->image->data = shmat(shmimg->shm_id, 0, 0);
+ if( (void*)-1 == (void*)(shmimg->image->data) ){ goto fail; }
+
+ shmimg->shm_seg = xcb_generate_id(connection),
+ error = xcb_request_check(connection,
+ xcb_shm_attach_checked(
+ connection,
+ shmimg->shm_seg, shmimg->shm_id, 0) );
+fail:
+ if( shmimg ){
+ if( shmimg->image ){
+ if( shmimg->image->data && error ){
+ shmdt(shmimg->image->data);
+ shmimg->image->data = NULL;
+ }
+ if( !shmimg->image->data ){
+ shmctl(shmimg->shm_id, IPC_RMID, 0);
+ shmimg->shm_id = -1;
+ }
+ }
+ if( 0 > shmimg->shm_id ){
+ xcb_image_destroy(shmimg->image);
+ shmimg->image = NULL;
+ }
+ if( !shmimg->image ){
+ free(shmimg);
+ shmimg = NULL;
+ }
+ }
+ free(error);
+
+ return shmimg;
+}
+
+static void shm_xcb_image_destroy(shm_xcb_image_t *shmimg)
+{
+ xcb_shm_detach(shmimg->connection, shmimg->shm_seg);
+ shmdt(shmimg->image->data);
+ shmctl(shmimg->shm_id, IPC_RMID, 0);
+ xcb_image_destroy(shmimg->image);
+ free(shmimg);
+}
+
+static void generate_image(
+ shm_xcb_image_t *shmimg,
+ unsigned t )
+{
+ for( unsigned j = 0; j < shmimg->image->height; ++j ){
+ uint8_t *const line = shmimg->image->data + j * shmimg->image->stride;
+ for( unsigned i = 0; i < shmimg->image->width; ++i ){
+ unsigned const bytes_per_pixel = shmimg->image->bpp/8;
+ uint8_t *pixel = line + i * bytes_per_pixel;
+
+ unsigned const a = (i + t);
+ unsigned const b = (j + (i >> 8) & 0xFF);
+ unsigned const c = (j >> 8) & 0xFF;
+
+ switch( bytes_per_pixel ){
+ case 4: pixel[3] = 0xFF; /* fallthrough */
+ case 3: pixel[2] = a & 0xFF; /* fallthrough */
+ case 2: pixel[1] = b & 0xFF; /* fallthrough */
+ case 1: pixel[0] = c & 0xFF; /* fallthrough */
+ default: break;
+ }
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ /* Open the connection to the X server */
+ xcb_connection_t *connection = xcb_connect(NULL, NULL);
+
+ /* Check that X MIT-SHM is available (should be). */
+ const xcb_query_extension_reply_t *shm_extension = xcb_get_extension_data(connection, &xcb_shm_id);
+ if( !shm_extension || !shm_extension->present ){
+ fprintf(stderr, "Query for X MIT-SHM extension failed.\n");
+ return 1;
+ }
+
+ shm_xcb_image_t *shmimg = shm_xcb_image_create(connection, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_DEPTH);
+ if( !shmimg ){
+ fprintf(stderr, "Creating shared memory image failed");
+ }
+
+ /* Get the first screen */
+ xcb_screen_t *const screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
+
+ /* Create a window */
+ uint32_t const window_mask = XCB_CW_EVENT_MASK;
+ uint32_t const window_values[] = { XCB_EVENT_MASK_EXPOSURE};
+ xcb_drawable_t const window = xcb_generate_id(connection);
+ xcb_create_window(connection,
+ XCB_COPY_FROM_PARENT, /* depth */
+ window, /* window Id */
+ screen->root, /* parent window */
+ 0, 0, /* x, y */
+ IMAGE_WIDTH, IMAGE_HEIGHT, /* width, height */
+ 0, /* border_width */
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
+ screen->root_visual, /* visual */
+ window_mask, window_values /* masks */
+ );
+
+ /* Create black (foreground) graphic context */
+ xcb_gcontext_t gc = xcb_generate_id( connection );
+ uint32_t const gc_mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
+ uint32_t const gc_values[] = {screen->black_pixel, 0};
+ xcb_create_gc(connection, gc, window, gc_mask, gc_values);
+
+ /* Map the window on the screen and flush*/
+ xcb_map_window(connection, window);
+ xcb_flush(connection);
+
+ /* Event loop */
+ unsigned counter = 0;
+ for( xcb_generic_event_t *event
+ ; (event = xcb_wait_for_event(connection))
+ ; free(event)
+ ){
+ switch( event->response_type & ~0x80 ){
+ case XCB_EXPOSE:
+ generate_image(shmimg, counter++);
+ xcb_shm_put_image(connection, window, gc,
+ shmimg->image->width, shmimg->image->height, 0, 0,
+ shmimg->image->width, shmimg->image->height, 0, 0,
+ shmimg->image->depth, shmimg->image->format, 0,
+ shmimg->shm_seg, 0);
+
+ /* flush the request */
+ xcb_flush(connection);
+ break;
+ default:
+ /* Unknown event type, ignore it */
+ break;
+ }
+
+ }
+
+ shm_xcb_image_destroy(shmimg);
+
+ return 0;
+}