diff options
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 Binary files differnew file mode 100644 index 0000000..966cc12 --- /dev/null +++ b/samples/OpenGL/frustum/screenshot.png 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; +} |