Added basic test mode for debug builds
This commit is contained in:
2
Makefile
2
Makefile
@@ -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
27
glava.c
@@ -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))) {
|
||||
|
||||
33
glx_wcb.c
33
glx_wcb.c
@@ -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
102
render.c
@@ -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; }
|
||||
|
||||
|
||||
6
render.h
6
render.h
@@ -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
33
shaders/test/1.frag
Normal 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
12
shaders/test/2.frag
Normal 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
2
shaders/test/3.frag
Normal file
@@ -0,0 +1,2 @@
|
||||
/* Assert that the premultiply step works */
|
||||
#include ":util/premultiply.frag"
|
||||
27
shaders/test_rc.glsl
Normal file
27
shaders/test_rc.glsl
Normal 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
|
||||
Reference in New Issue
Block a user