From fc598a3404f9e856300230c0f21ec4a5f302993a Mon Sep 17 00:00:00 2001 From: blackle Date: Tue, 2 Apr 2019 01:13:23 -0400 Subject: [PATCH] Add xlib example --- .gitignore | 3 +- Makefile | 10 +++- README.md | 10 +++- xlib-opengl.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 xlib-opengl.c diff --git a/.gitignore b/.gitignore index ff70706..01186f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.elf gtk-webkit gtk-opengl -shader.h +xlib-opengl +shader.h \ No newline at end of file diff --git a/Makefile b/Makefile index ba0a6fa..cc223cf 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -all : gtk-webkit gtk-opengl +all : gtk-webkit gtk-opengl xlib-opengl .PHONY: clean @@ -16,12 +16,18 @@ gtk-webkit.elf : gtk-webkit.c Makefile gtk-opengl.elf : gtk-opengl.c shader.h Makefile gcc -o $@ $< `pkg-config --cflags gtk+-3.0` -lglib-2.0 -lGL -lgtk-3 -lgdk-3 -lgobject-2.0 -no-pie -fno-plt -Os -std=gnu11 -nostartfiles -nostdlib +xlib-opengl.elf : xlib-opengl.c shader.h Makefile + gcc -o $@ $< -lX11 -lGL -lcairo -lXrandr -no-pie -fno-plt -Os -std=gnu11 -nostartfiles -nostdlib + gtk-webkit : gtk-webkit_opt.elf.packed mv $< $@ gtk-opengl : gtk-opengl_opt.elf.packed mv $< $@ +xlib-opengl : xlib-opengl_opt.elf.packed + mv $< $@ + #all the rest of these rules just takes a compiled elf file and generates a packed version of it with vondehi %_opt.elf : %.elf Makefile @@ -50,4 +56,4 @@ gtk-opengl : gtk-opengl_opt.elf.packed wc -c $@ clean : - -rm *.elf shader.h gtk-webkit + -rm *.elf shader.h gtk-webkit gtk-opengl xlib-opengl diff --git a/README.md b/README.md index ce6f015..1bb578a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ # Linux-OpenGL-Examples -Some code examples for opening windows for various purposes in very few bytes. +Some code examples for opening windows for various purposes in very few bytes. Unfortunately each example does its own thing, so comparing the sizes is an apple to oranges thing. ## gtk-opengl - 1585 bytes -Example code for opening a glsl shader fullscreen with gtk. Closes with the standard alt+f4 on Ubuntu. Shaders get passed an iTime uniform in seconds. App closes automatically after 10 seconds. +Example code for opening a glsl shader fullscreen with gtk. Closes with the standard ALT+F4 on Ubuntu. Shaders get passed an iTime uniform in seconds. App closes automatically after 10 seconds. ## gtk-webkit - 1074 bytes -Example code for opening an html page fullscreen with gtk. Closes with the standard alt+f4 on Ubuntu. WebGL is enabled however is not used in the example. Testing with webkit gtk has found that most(?) shadertoy shaders seem to work. It has yet to be seen if initializing a shader in javascript takes fewer bytes than with gtk's opengl code. +Example code for opening an html page fullscreen with gtk. Closes with the standard ALT+F4 on Ubuntu. WebGL is enabled however is not used in the example. Testing with webkit gtk has found that most(?) shadertoy shaders seem to work. It has yet to be seen if initializing a shader in javascript takes fewer bytes than with gtk's opengl code. + +## xlib-opengl + +Example code for opening a glsl shader fullscreen with vanilla xlib. Unlike gtk-opengl, this does not pass in an iTime or render the shader more than once, and also must be closed with ESC. This code is based on the code for Cenotaph For Soda, a 4k gfx demo for Revision 2018 diff --git a/xlib-opengl.c b/xlib-opengl.c new file mode 100644 index 0000000..bee6fe2 --- /dev/null +++ b/xlib-opengl.c @@ -0,0 +1,159 @@ +#define GL_GLEXT_PROTOTYPES why +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "shader.h" + +#define CANVAS_WIDTH 1920 +#define CANVAS_HEIGHT 1080 +// #define DEBUG true + +static unsigned char fbdata[4 * CANVAS_HEIGHT * CANVAS_WIDTH]; + +void _start() { + asm volatile("sub $8, %rsp\n"); + + Display* dpy = XOpenDisplay(NULL); + Window root = DefaultRootWindow(dpy); + + static GLint att[] = { GLX_RGBA, None }; + XVisualInfo* vi = glXChooseVisual(dpy, 0, att); + + //I really hate this and I wish this call was unneeded. it feels useless + Colormap cmap = XCreateColormap(dpy, root, vi->visual, AllocNone); + + //hide cursor + XColor xcolor; + Pixmap csr= XCreatePixmap(dpy,root,1,1,1); + Cursor cursor= XCreatePixmapCursor(dpy,csr,csr,&xcolor,&xcolor,1,1); + + //this enables things like events, fullscreen, and sets the invisible cursor + static XSetWindowAttributes swa = { .override_redirect = 1, .event_mask = ExposureMask | KeyPressMask }; + swa.colormap = cmap; + swa.cursor = cursor; + Window win = XCreateWindow(dpy, root, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask | CWOverrideRedirect | CWCursor, &swa); + + //this actually opens the window + XMapWindow(dpy, win); + + //now we can do opengl calls!!!! + GLXContext glc = glXCreateContext(dpy, vi, NULL, 1); + + #ifdef DEBUG + if (glc == NULL) { + return; + } + #endif + + glXMakeCurrent(dpy, win, glc); + + glClear(GL_COLOR_BUFFER_BIT); + + //oh yeah grab the keyboard + XGrabKeyboard(dpy, win, true, GrabModeAsync, GrabModeAsync, CurrentTime); + + //create a floating point backing texture for a framebuffer + GLuint textureA; + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &textureA); + glBindTexture(GL_TEXTURE_2D, textureA); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, CANVAS_WIDTH, CANVAS_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, fbdata); + + //create a framebuffer we can render everything to + GLuint fboA; + glGenFramebuffers(1, &fboA); + glBindFramebuffer(GL_FRAMEBUFFER, fboA); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, textureA, 0); + + // compile shader + GLuint f = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(f, 1, &shader_frag, NULL); + glCompileShader(f); + + #ifdef DEBUG + GLint isCompiled = 0; + glGetShaderiv(f, GL_COMPILE_STATUS, &isCompiled); + if(isCompiled == GL_FALSE) { + GLint maxLength = 0; + glGetShaderiv(f, GL_INFO_LOG_LENGTH, &maxLength); + + char* error = malloc(maxLength); + glGetShaderInfoLog(f, maxLength, &maxLength, error); + printf("%s\n", error); + + exit(-10); + } + #endif + + // link shader + GLuint p = glCreateProgram(); + glAttachShader(p,f); + glLinkProgram(p); + + #ifdef DEBUG + GLint isLinked = 0; + glGetProgramiv(p, GL_LINK_STATUS, (int *)&isLinked); + if (isLinked == GL_FALSE) { + GLint maxLength = 0; + glGetProgramiv(p, GL_INFO_LOG_LENGTH, &maxLength); + + char* error = malloc(maxLength); + glGetProgramInfoLog(p, maxLength, &maxLength,error); + printf("%s\n", error); + + exit(-10); + } + #endif + + glUseProgram(p); + + //switch to using our framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, fboA); + + //clear it + // glClear(GL_COLOR_BUFFER_BIT); + + //enable additive blending so we don't have to do so in the shader + glEnable(GL_BLEND); + // glBlendEquationSeparate( GL_FUNC_ADD, GL_FUNC_ADD); + glBlendFunc( GL_ONE , GL_ONE_MINUS_SRC_ALPHA); + + // glFinish(); + glRecti(-1,-1,1,1); + + //blit our framebuffer to the screen + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fboA); + + glBlitFramebuffer(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + static XEvent xev; + while(1) { + XNextEvent(dpy, &xev); + + //wait for escape key, then exit without glib :3 + if(xev.type == KeyPress && xev.xkey.keycode == 0x09) { + //blackle mori no likey AT&T + asm volatile(".intel_syntax noprefix"); + asm volatile("push 60"); + asm volatile("pop rax"); + asm volatile("xor edi, edi"); + asm volatile("syscall"); + asm volatile(".att_syntax prefix"); + __builtin_unreachable(); + } + } +}