@ -66,6 +66,7 @@
/* Possible options that affect the displayed image */
/* Possible options that affect the displayed image */
# define OPT_IMMEDIATE (1 << 0) /* create wl_buffer immediately */
# define OPT_IMMEDIATE (1 << 0) /* create wl_buffer immediately */
# define OPT_IMPLICIT_SYNC (1 << 1) /* force implicit sync */
# define OPT_IMPLICIT_SYNC (1 << 1) /* force implicit sync */
# define OPT_MANDELBROT (1 << 2) /* render mandelbrot */
# define BUFFER_FORMAT DRM_FORMAT_XRGB8888
# define BUFFER_FORMAT DRM_FORMAT_XRGB8888
# define MAX_BUFFER_PLANES 4
# define MAX_BUFFER_PLANES 4
@ -147,6 +148,7 @@ struct window {
GLuint color ;
GLuint color ;
GLuint offset_uniform ;
GLuint offset_uniform ;
} gl ;
} gl ;
bool render_mandelbrot ;
} ;
} ;
static sig_atomic_t running = 1 ;
static sig_atomic_t running = 1 ;
@ -485,6 +487,40 @@ static const char *frag_shader_text =
" gl_FragColor = v_color; \n "
" gl_FragColor = v_color; \n "
" } \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
static GLuint
create_shader ( const char * source , GLenum shader_type )
create_shader ( const char * source , GLenum shader_type )
{
{
@ -536,8 +572,14 @@ create_and_link_program(GLuint vert, GLuint frag)
static bool
static bool
window_set_up_gl ( struct window * window )
window_set_up_gl ( struct window * window )
{
{
GLuint vert = create_shader ( vert_shader_text , GL_VERTEX_SHADER ) ;
GLuint vert = create_shader (
GLuint frag = create_shader ( frag_shader_text , GL_FRAGMENT_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 ) ;
window - > gl . program = create_and_link_program ( vert , frag ) ;
@ -582,7 +624,7 @@ destroy_window(struct window *window)
}
}
static struct 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 ;
struct window * window ;
int i ;
int i ;
@ -651,6 +693,8 @@ create_window(struct display *display, int width, int height)
goto error ;
goto error ;
}
}
window - > render_mandelbrot = opts & OPT_MANDELBROT ;
if ( ! window_set_up_gl ( window ) )
if ( ! window_set_up_gl ( window ) )
goto error ;
goto error ;
@ -755,6 +799,63 @@ render(struct window *window, struct buffer *buffer)
glDisableVertexAttribArray ( window - > gl . color ) ;
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
static void
buffer_fenced_release ( void * data ,
buffer_fenced_release ( void * data ,
struct zwp_linux_buffer_release_v1 * release ,
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 )
if ( buffer - > release_fence_fd > = 0 )
wait_for_buffer_release_fence ( buffer ) ;
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 ) {
if ( window - > display - > use_explicit_sync ) {
int fence_fd = create_egl_fence_fd ( window ) ;
int fence_fd = create_egl_fence_fd ( window ) ;
@ -1295,7 +1399,9 @@ print_usage_and_exit(void)
" \n \t \t the window size in pixels (default: 256) \n "
" \n \t \t the window size in pixels (default: 256) \n "
" \t '-e,--explicit-sync=<>' "
" \t '-e,--explicit-sync=<>' "
" \n \t \t 0 to disable explicit sync, "
" \n \t \t 0 to disable explicit sync, "
" \n \t \t 1 to enable explicit sync (default: 1) \n " ) ;
" \n \t \t 1 to enable explicit sync (default: 1) \n "
" \t '-m,--mandelbrot' "
" \n \t \t render a mandelbrot set with multiple draw calls \n " ) ;
exit ( 0 ) ;
exit ( 0 ) ;
}
}
@ -1328,12 +1434,13 @@ main(int argc, char **argv)
{ " drm-render-node " , required_argument , 0 , ' d ' } ,
{ " drm-render-node " , required_argument , 0 , ' d ' } ,
{ " size " , required_argument , 0 , ' s ' } ,
{ " size " , required_argument , 0 , ' s ' } ,
{ " explicit-sync " , required_argument , 0 , ' e ' } ,
{ " explicit-sync " , required_argument , 0 , ' e ' } ,
{ " mandelbrot " , no_argument , 0 , ' m ' } ,
{ " help " , no_argument , 0 , ' h ' } ,
{ " help " , no_argument , 0 , ' h ' } ,
{ 0 , 0 , 0 , 0 }
{ 0 , 0 , 0 , 0 }
} ;
} ;
while ( ( c = getopt_long ( argc , argv , " hi:d:s:e: " ,
while ( ( c = getopt_long ( argc , argv , " hi:d:s:e:m " ,
long_options , & option_index ) ) ! = - 1 ) {
long_options , & option_index ) ) ! = - 1 ) {
switch ( c ) {
switch ( c ) {
case ' i ' :
case ' i ' :
if ( is_true ( optarg ) )
if ( is_true ( optarg ) )
@ -1349,6 +1456,9 @@ main(int argc, char **argv)
if ( ! is_true ( optarg ) )
if ( ! is_true ( optarg ) )
opts | = OPT_IMPLICIT_SYNC ;
opts | = OPT_IMPLICIT_SYNC ;
break ;
break ;
case ' m ' :
opts | = OPT_MANDELBROT ;
break ;
default :
default :
print_usage_and_exit ( ) ;
print_usage_and_exit ( ) ;
}
}
@ -1357,7 +1467,7 @@ main(int argc, char **argv)
display = create_display ( drm_render_node , opts ) ;
display = create_display ( drm_render_node , opts ) ;
if ( ! display )
if ( ! display )
return 1 ;
return 1 ;
window = create_window ( display , window_size , window_size ) ;
window = create_window ( display , window_size , window_size , opts ) ;
if ( ! window )
if ( ! window )
return 1 ;
return 1 ;