clients: Add a mandelbrot set shader to simple-dmabuf-egl

Support drawing a mandelbrot set in the fragment shader, rendering it
with separate draw calls, one for each cell in a virtual 4x4 grid. This
more complex and heavy drawing will potentially help us to visually
discover any present or future explicit synchronization issues.

The mandelbrot set rendering is enabled with the -m/--mandelbrot
command-line switch.

Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
This commit is contained in:
Alexandros Frantzis 2019-01-29 16:22:45 +02:00 committed by Pekka Paalanen
parent a95bb6f7e5
commit 7261edfe36
1 changed files with 118 additions and 8 deletions

View File

@ -66,6 +66,7 @@
/* Possible options that affect the displayed image */
#define OPT_IMMEDIATE (1 << 0) /* create wl_buffer immediately */
#define OPT_IMPLICIT_SYNC (1 << 1) /* force implicit sync */
#define OPT_MANDELBROT (1 << 2) /* render mandelbrot */
#define BUFFER_FORMAT DRM_FORMAT_XRGB8888
#define MAX_BUFFER_PLANES 4
@ -147,6 +148,7 @@ struct window {
GLuint color;
GLuint offset_uniform;
} gl;
bool render_mandelbrot;
};
static sig_atomic_t running = 1;
@ -485,6 +487,40 @@ static const char *frag_shader_text =
" gl_FragColor = v_color;\n"
"}\n";
static const char *vert_shader_mandelbrot_text =
"uniform float offset;\n"
"attribute vec4 pos;\n"
"varying vec2 v_pos;\n"
"void main() {\n"
" v_pos = pos.xy;\n"
" gl_Position = pos + vec4(offset, offset, 0.0, 0.0);\n"
"}\n";
/* Mandelbrot set shader using the escape time algorithm. */
static const char *frag_shader_mandelbrot_text =
"precision mediump float;\n"
"varying vec2 v_pos;\n"
"void main() {\n"
" const int max_iteration = 500;\n"
" // Scale and translate position to get a nice mandelbrot drawing for\n"
" // the used v_pos x and y range (-0.5 to 0.5).\n"
" float x0 = 3.0 * v_pos.x - 0.5;\n"
" float y0 = 3.0 * v_pos.y;\n"
" float x = 0.0;\n"
" float y = 0.0;\n"
" int iteration = 0;\n"
" while (x * x + y * y <= 4.0 && iteration < max_iteration) {\n"
" float xtemp = x * x - y * y + x0;\n"
" y = 2.0 * x * y + y0;\n"
" x = xtemp;\n"
" ++iteration;\n"
" }\n"
" float red = iteration == max_iteration ?\n"
" 0.0 : 1.0 - fract(float(iteration) / 20.0);\n"
" gl_FragColor = vec4(red, 0.0, 0.0, 1.0);\n"
"}\n";
static GLuint
create_shader(const char *source, GLenum shader_type)
{
@ -536,8 +572,14 @@ create_and_link_program(GLuint vert, GLuint frag)
static bool
window_set_up_gl(struct window *window)
{
GLuint vert = create_shader(vert_shader_text, GL_VERTEX_SHADER);
GLuint frag = create_shader(frag_shader_text, GL_FRAGMENT_SHADER);
GLuint vert = create_shader(
window->render_mandelbrot ? vert_shader_mandelbrot_text :
vert_shader_text,
GL_VERTEX_SHADER);
GLuint frag = create_shader(
window->render_mandelbrot ? frag_shader_mandelbrot_text :
frag_shader_text,
GL_FRAGMENT_SHADER);
window->gl.program = create_and_link_program(vert, frag);
@ -582,7 +624,7 @@ destroy_window(struct window *window)
}
static struct window *
create_window(struct display *display, int width, int height)
create_window(struct display *display, int width, int height, int opts)
{
struct window *window;
int i;
@ -651,6 +693,8 @@ create_window(struct display *display, int width, int height)
goto error;
}
window->render_mandelbrot = opts & OPT_MANDELBROT;
if (!window_set_up_gl(window))
goto error;
@ -755,6 +799,63 @@ render(struct window *window, struct buffer *buffer)
glDisableVertexAttribArray(window->gl.color);
}
static void
render_mandelbrot(struct window *window, struct buffer *buffer)
{
/* Complete a movement iteration in 5000 ms. */
static const uint64_t iteration_ms = 5000;
/* Split drawing in a square grid consisting of grid_side * grid_side
* cells. */
static const int grid_side = 4;
GLfloat norm_cell_side = 1.0 / grid_side;
int num_cells = grid_side * grid_side;
GLfloat offset;
struct timeval tv;
uint64_t time_ms;
int i;
gettimeofday(&tv, NULL);
time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
/* Split time_ms in repeating windows of [0, iteration_ms) and map them
* to offsets in the [-0.5, 0.5) range. */
offset = (time_ms % iteration_ms) / (float) iteration_ms - 0.5;
/* Direct all GL draws to the buffer through the FBO */
glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo);
glViewport(0, 0, window->width, window->height);
glUniform1f(window->gl.offset_uniform, offset);
glClearColor(0.6, 0.6, 0.6, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
for (i = 0; i < num_cells; ++i) {
/* Calculate the vertex coordinates of the current grid cell. */
int row = i / grid_side;
int col = i % grid_side;
GLfloat left = -0.5 + norm_cell_side * col;
GLfloat right = left + norm_cell_side;
GLfloat top = 0.5 - norm_cell_side * row;
GLfloat bottom = top - norm_cell_side;
GLfloat verts[4][2] = {
{ left, bottom },
{ left, top },
{ right, bottom },
{ right, top }
};
/* ... and draw it. */
glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
glEnableVertexAttribArray(window->gl.pos);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(window->gl.pos);
}
}
static void
buffer_fenced_release(void *data,
struct zwp_linux_buffer_release_v1 *release,
@ -836,7 +937,10 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
if (buffer->release_fence_fd >= 0)
wait_for_buffer_release_fence(buffer);
render(window, buffer);
if (window->render_mandelbrot)
render_mandelbrot(window, buffer);
else
render(window, buffer);
if (window->display->use_explicit_sync) {
int fence_fd = create_egl_fence_fd(window);
@ -1295,7 +1399,9 @@ print_usage_and_exit(void)
"\n\t\tthe window size in pixels (default: 256)\n"
"\t'-e,--explicit-sync=<>'"
"\n\t\t0 to disable explicit sync, "
"\n\t\t1 to enable explicit sync (default: 1)\n");
"\n\t\t1 to enable explicit sync (default: 1)\n"
"\t'-m,--mandelbrot'"
"\n\t\trender a mandelbrot set with multiple draw calls\n");
exit(0);
}
@ -1328,12 +1434,13 @@ main(int argc, char **argv)
{"drm-render-node", required_argument, 0, 'd' },
{"size", required_argument, 0, 's' },
{"explicit-sync", required_argument, 0, 'e' },
{"mandelbrot", no_argument, 0, 'm' },
{"help", no_argument , 0, 'h' },
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "hi:d:s:e:",
long_options, &option_index)) != -1) {
while ((c = getopt_long(argc, argv, "hi:d:s:e:m",
long_options, &option_index)) != -1) {
switch (c) {
case 'i':
if (is_true(optarg))
@ -1349,6 +1456,9 @@ main(int argc, char **argv)
if (!is_true(optarg))
opts |= OPT_IMPLICIT_SYNC;
break;
case 'm':
opts |= OPT_MANDELBROT;
break;
default:
print_usage_and_exit();
}
@ -1357,7 +1467,7 @@ main(int argc, char **argv)
display = create_display(drm_render_node, opts);
if (!display)
return 1;
window = create_window(display, window_size, window_size);
window = create_window(display, window_size, window_size, opts);
if (!window)
return 1;