Added basic test mode for debug builds

This commit is contained in:
Jarcode
2019-03-12 16:18:46 -07:00
parent 094dec9b00
commit d640ac5d3c
9 changed files with 247 additions and 9 deletions

View File

@@ -123,7 +123,7 @@ SHADERTARGET = $(shell readlink -m "$(DESTDIR)$(SHADERDIR)")
install:
install -Dm755 glava $(EXECTARGET)
install -d $(SHADERTARGET)
cp -Rv shaders/* $(SHADERTARGET)
shopt -s extglob && cp -Rv shaders/!(test|test_rc.glsl) $(SHADERTARGET)
.PHONY: uninstall
uninstall:

27
glava.c
View File

@@ -218,6 +218,9 @@ static struct option p_opts[] = {
{"backend", required_argument, 0, 'b'},
{"stdin", optional_argument, 0, 'i'},
{"version", no_argument, 0, 'V'},
#ifdef GLAVA_DEBUG
{"run-tests", no_argument, 0, 'T'},
#endif
{0, 0, 0, 0 }
};
@@ -295,6 +298,12 @@ int main(int argc, char** argv) {
exit(EXIT_FAILURE);
}
}
#ifdef GLAVA_DEBUG
case 'T': {
entry = "test_rc.glsl";
rd_enable_test_mode();
}
#endif
}
}
@@ -388,15 +397,31 @@ int main(int argc, char** argv) {
}
pthread_mutex_unlock(&audio.mutex);
if (!rd_update(rd, lb, rb, rd->bufsize_request, modified)) {
bool ret = rd_update(rd, lb, rb, rd->bufsize_request, modified);
if (!ret) {
/* Sleep for 50ms and then attempt to render again */
struct timespec tv = {
.tv_sec = 0, .tv_nsec = 50 * 1000000
};
nanosleep(&tv, NULL);
}
#ifdef GLAVA_DEBUG
if (ret && rd_get_test_mode())
break;
#endif
}
#ifdef GLAVA_DEBUG
if (rd_get_test_mode()) {
if (rd_test_evaluate(rd)) {
fprintf(stderr, "Test results did not match expected output\n");
fflush(stderr);
exit(EXIT_FAILURE);
}
}
#endif
audio.terminate = 1;
int return_status;
if ((return_status = pthread_join(thread, NULL))) {

View File

@@ -162,6 +162,11 @@ __GLXextFuncPtr (*glXGetProcAddressARB) (const GLubyte *);
void (*glXSwapBuffers) (Display* dpy, GLXDrawable drawable);
void (*glXDestroyContext) (Display* dpy, GLXContext ctx);
Bool (*glXQueryVersion) (Display* dpy, int* major, int* minor);
#ifdef GLAVA_DEBUG
GLXPixmap (*glXCreateGLXPixmap) (Display* dpy, XVisualInfo* vis, Pixmap pixmap);
static Pixmap test_pixmap;
static GLXPixmap test_glxpm;
#endif
extern struct gl_wcb wcb_glx;
@@ -227,6 +232,9 @@ static void init(void) {
resolve(glXSwapBuffers);
resolve(glXDestroyContext);
resolve(glXQueryVersion);
#ifdef GLAVA_DEBUG
resolve(glXCreateGLXPixmap);
#endif
intern(_MOTIF_WM_HINTS, false);
intern(WM_DELETE_WINDOW, true);
@@ -488,7 +496,17 @@ static void* create_and_bind(const char* name, const char* class,
XSync(display, False);
#ifdef GLAVA_DEBUG
if (rd_get_test_mode()) {
test_pixmap = XCreatePixmap(display, w->w, d, h,
DefaultDepth(display, DefaultScreen(display)));
test_glxpm = glXCreateGLXPixmap(display, vi, test_pixmap);
glXMakeCurrent(display, test_glxpm, w->context);
} else
glXMakeCurrent(display, w->w, w->context);
#else
glXMakeCurrent(display, w->w, w->context);
#endif
gladLoadGL();
GLXDrawable drawable = glXGetCurrentDrawable();
@@ -538,6 +556,10 @@ static void set_geometry(struct glxwin* w, int x, int y, int d, int h) {
}
static void set_visible(struct glxwin* w, bool visible) {
#ifdef GLAVA_DEBUG
if (rd_get_test_mode())
return;
#endif
if (visible) {
XMapWindow(display, w->w);
switch (w->override_state) {
@@ -553,6 +575,10 @@ static void set_visible(struct glxwin* w, bool visible) {
static bool should_close (struct glxwin* w) { return w->should_close; }
static bool bg_changed (struct glxwin* w) { return w->bg_changed; }
static bool should_render(struct glxwin* w) {
#ifdef GLAVA_DEBUG
if (rd_get_test_mode())
return true;
#endif
/* For nearly all window managers, windows are 'minimized' by unmapping parent windows.
VisibilityNotify events are not sent in these instances, so we have to read window
attributes to see if our window isn't viewable. */
@@ -563,7 +589,14 @@ static bool should_render(struct glxwin* w) {
}
static void swap_buffers(struct glxwin* w) {
#ifdef GLAVA_DEBUG
if (rd_get_test_mode())
glXSwapBuffers(display, test_glxpm);
else
glXSwapBuffers(display, w->w);
#else
glXSwapBuffers(display, w->w);
#endif
process_events(w);
}

102
render.c
View File

@@ -139,9 +139,32 @@ struct gl_data {
float* interpolate_buf[6];
int geometry[4];
int stdin_type;
#ifdef GLAVA_DEBUG
struct {
float r, g, b, a;
} test_eval_color;
bool debug_verbose;
#endif
};
#ifdef GLAVA_DEBUG
static bool test_mode = false;
static struct gl_sfbo test_sfbo = {
.name = "test",
.shader = 0,
.indirect = false,
.nativeonly = false,
.binds = NULL,
.binds_sz = 0
};
void rd_enable_test_mode(void) {
test_mode = true;
}
bool rd_get_test_mode(void) {
return test_mode;
}
#endif
/* load shader file */
static GLuint shaderload(const char* rpath,
@@ -258,8 +281,10 @@ static GLuint shaderload(const char* rpath,
fprintf(stderr, "Shader compilation failed for '%s':\n", path);
fwrite(ebuf, sizeof(GLchar), ilen - 1, stderr);
#ifdef GLAVA_DEBUG
if (gl->debug_verbose) {
fprintf(stderr, "Processed shader source for '%s':\n", path);
fwrite(buf, sizeof(GLchar), sl, stderr);
}
#endif
free_ebuf:
@@ -780,7 +805,11 @@ struct renderer* rd_new(const char** paths, const char* entry,
.geometry = { 0, 0, 500, 400 },
.clear_color = { 0.0F, 0.0F, 0.0F, 0.0F },
.clickthrough = false,
.stdin_type = stdin_type
.stdin_type = stdin_type,
#ifdef GLAVA_DEBUG
.test_eval_color = { 0.0F, 0.0F, 0.0F, 0.0F },
.debug_verbose = verbose
#endif
};
bool forced = force_backend != NULL;
@@ -898,6 +927,23 @@ struct renderer* rd_new(const char** paths, const char* entry,
}
})
},
#ifdef GLAVA_DEBUG
{
.name = "settesteval", .fmt = "s",
.handler = RHANDLER(name, args, {
float* results[] = {
&gl->test_eval_color.r,
&gl->test_eval_color.g,
&gl->test_eval_color.b,
&gl->test_eval_color.a
};
if (!ext_parse_color((char*) args[0], 2, results)) {
fprintf(stderr, "Invalid value for `setbg` request: '%s'\n", (char*) args[0]);
exit(EXIT_FAILURE);
}
})
},
#endif
{
.name = "setbgf", .fmt = "ffff",
.handler = RHANDLER(name, args, {
@@ -1358,6 +1404,14 @@ struct renderer* rd_new(const char** paths, const char* entry,
gl->stages = stages;
gl->stages_sz = count;
#ifdef GLAVA_DEBUG
{
int w, h;
gl->wcb->get_fbsize(gl->w, &w, &h);
setup_sfbo(&test_sfbo, w, h);
}
#endif
{
struct gl_sfbo* final = NULL;
for (size_t t = 0; t < gl->stages_sz; ++t) {
@@ -1504,6 +1558,9 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
setup_sfbo(&gl->stages[t], ww, wh);
}
}
#ifdef GLAVA_DEBUG
setup_sfbo(&test_sfbo, ww, wh);
#endif
}
/* Resize and grab new background data if needed */
@@ -1631,6 +1688,12 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
if (current->indirect)
glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
#ifdef GLAVA_DEBUG
if (!current->indirect && test_mode) {
glBindFramebuffer(GL_FRAMEBUFFER, test_sfbo.fbo);
}
#endif
glClear(GL_COLOR_BUFFER_BIT);
if (!current->indirect && gl->copy_desktop) {
@@ -1910,6 +1973,43 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
return true;
}
#ifdef GLAVA_DEBUG
bool rd_test_evaluate(struct renderer* r) {
int w, h;
struct gl_data* gl = r->gl;
gl->wcb->get_fbsize(gl->w, &w, &h);
printf("Reading pixels from final framebuffer (%dx%d)\n", w, h);
float margin = 1.0 / (255.0F * 2.0F);
float eval[4] = {
gl->test_eval_color.r,
gl->test_eval_color.g,
gl->test_eval_color.b,
gl->test_eval_color.a
};
bool err = false;
for (int x = 0; x < w; ++x) {
for (int y = 0; y < h; ++y) {
float ret[4];
glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, &ret);
if (ret[0] < eval[0] - margin || ret[0] > eval[0] + margin ||
ret[1] < eval[1] - margin || ret[1] > eval[1] + margin ||
ret[2] < eval[2] - margin || ret[2] > eval[2] + margin ||
ret[3] < eval[3] - margin || ret[3] > eval[3] + margin) {
fprintf(stderr, "px (%d,%d) failed test, (%f,%f,%f,%f)"
" is not within margins for (%f,%f,%f,%f)\n",
x, y,
(double) ret[0], (double) ret[1], (double) ret[2], (double) ret[3],
(double) eval[0], (double) eval[1], (double) eval[2], (double) eval[3]);
err = true;
goto end_test;
}
}
}
end_test:
return err;
}
#endif
void* rd_get_impl_window (struct renderer* r) { return r->gl->w; }
struct gl_wcb* rd_get_wcb (struct renderer* r) { return r->gl->wcb; }

View File

@@ -24,6 +24,12 @@ typedef struct renderer {
struct gl_data* gl;
} renderer;
#ifdef GLAVA_DEBUG
void rd_enable_test_mode(void);
bool rd_get_test_mode (void);
bool rd_test_evaluate (struct renderer*);
#endif
struct renderer* rd_new (const char** paths, const char* entry,
const char** requests, const char* force_backend,
int stdin_type, bool auto_desktop,

33
shaders/test/1.frag Normal file
View File

@@ -0,0 +1,33 @@
/* Request transforms and basic uniforms to assert nothing here breaks */
#include ":util/smooth.glsl"
in vec4 gl_FragCoord;
#request uniform "screen" screen
uniform ivec2 screen;
#request uniform "audio_sz" audio_sz
uniform int audio_sz;
#request uniform "audio_l" audio_l
#request transform audio_l "window"
#request transform audio_l "fft"
#request transform audio_l "gravity"
#request transform audio_l "avg"
uniform sampler1D audio_l;
#request uniform "audio_r" audio_r
#request transform audio_r "window"
#request transform audio_r "fft"
#request transform audio_r "gravity"
#request transform audio_r "avg"
uniform sampler1D audio_r;
out vec4 fragment;
void main() {
float dummy_result0 = smooth_audio(audio_l, audio_sz, gl_FragCoord.x / float(screen.x));
float dummy_result1 = smooth_audio(audio_r, audio_sz, gl_FragCoord.x / float(screen.x));
fragment = vec4(1.0, 0, 0, float(1) / float(3));
}

12
shaders/test/2.frag Normal file
View File

@@ -0,0 +1,12 @@
/* Pass the initial results to a dummy shader to assert that linking works correctly */
in vec4 gl_FragCoord;
#request uniform "prev" tex
uniform sampler2D tex; /* screen texture */
out vec4 fragment; /* output */
void main() {
fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);
}

2
shaders/test/3.frag Normal file
View File

@@ -0,0 +1,2 @@
/* Assert that the premultiply step works */
#include ":util/premultiply.frag"

27
shaders/test_rc.glsl Normal file
View File

@@ -0,0 +1,27 @@
#request mod test
#request setfloating false
#request setdecorated true
#request setfocused false
#request setmaximized false
#request setopacity "native"
#request setmirror false
#request setversion 3 3
#request setshaderversion 330
#request settitle "GLava"
#request setgeometry 0 0 640 640
#request setbg 00000000
#request setxwintype "desktop"
#request setclickthrough false
#request setsource "auto"
#request setswap 0
#request setinterpolate true
#request setframerate 0
#request setfullscreencheck false
#request setprintframes true
#request setsamplesize 1024/
#request setbufsize 4096
#request setsamplerate 22050
#request setforcegeometry false
#request setforceraised false
#request setbufscale 1
#request settesteval 55000055