Esempio n. 1
0
    def draw(self):
        if self._glsl:
            fragment = fragment_template % self._glsl
            self._glsl = None

            # Check to see if the shader will compile successfully before we
            # set it. We do this here because the ShaderWatcher runs in a
            # different thread and so can't access the GL context.

            frag_handle = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
            gl.glShaderSource(frag_handle, fragment)
            gl.glCompileShader(frag_handle)
            status = gl.glGetShaderParameter(frag_handle, gl.GL_COMPILE_STATUS)
            if not status:
                errors = gl.glGetShaderInfoLog(frag_handle)
                errors = self.process_errors(errors)
                print("Shader failed to compile:", file=sys.stderr)
                print(errors, file=sys.stderr)

                # Switch to error shader

                self._glsl = error_shader
                self.update()
            else:
                self.program.set_shaders(vertex, fragment)
            gl.glDeleteShader(frag_handle)

        if self._interactive:
            self.program.draw()

            if self._ffmpeg_pipe is not None:
                img = _screenshot()
                self.write_video_frame(img)

            self._render_frame_index += 1
            if self._render_frame_count is not None and self._render_frame_index >= self._render_frame_count:
                app.quit()
                return

            self.advance_time()
        else:
            with self._fbo:
                rs = list(self._render_size)

                if self._tile_coord[0] + rs[0] > self._output_size[0]:
                    rs[0] = self._output_size[0] - self._tile_coord[0]

                if self._tile_coord[1] + rs[1] > self._output_size[1]:
                    rs[1] = self._output_size[1] - self._tile_coord[1]

                gloo.set_viewport(0, 0, *rs)
                self.program['iOffset'] = self._tile_coord
                self.program.draw()
                img = _screenshot()
                row = self._output_size[1] - self._tile_coord[1] - rs[1]
                col = self._tile_coord[0]
                self._img[row:row + rs[1], col:col + rs[0], :] = img
    def draw(self):
        if self._glsl:
            fragment = fragment_template % self._glsl
            self._glsl = None

            # Check to see if the shader will compile successfully before we
            # set it. We do this here because the ShaderWatcher runs in a
            # different thread and so can't access the GL context.

            frag_handle = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
            gl.glShaderSource(frag_handle, fragment)
            gl.glCompileShader(frag_handle)
            status = gl.glGetShaderParameter(frag_handle, gl.GL_COMPILE_STATUS)
            if not status:
                errors = gl.glGetShaderInfoLog(frag_handle)
                errors = self.process_errors(errors)
                print("Shader failed to compile:", file=sys.stderr)
                print(errors, file=sys.stderr)

                # Switch to error shader

                self._glsl = error_shader
                self.update()
            else:
                self.program.set_shaders(vertex, fragment)
            gl.glDeleteShader(frag_handle)

        if self._interactive:
            self.program.draw()

            if self._ffmpeg_pipe is not None:
                img = _screenshot()
                self.write_video_frame(img)

            self._render_frame_index += 1
            if self._render_frame_count is not None and self._render_frame_index >= self._render_frame_count:
                app.quit()
                return

            self.advance_time()
        else:
            with self._fbo:
                rs = list(self._render_size)

                if self._tile_coord[0] + rs[0] > self._output_size[0]:
                    rs[0] = self._output_size[0] - self._tile_coord[0]

                if self._tile_coord[1] + rs[1] > self._output_size[1]:
                    rs[1] = self._output_size[1] - self._tile_coord[1]

                gloo.set_viewport(0, 0, *rs)
                self.program['iOffset'] = self._tile_coord
                self.program.draw()
                img = _screenshot()
                row = self._output_size[1] - self._tile_coord[1] - rs[1]
                col = self._tile_coord[0]
                self._img[row:row + rs[1], col:col + rs[0], :] = img
Esempio n. 3
0
def _prepare_vis():
    
    objects = []
    
    # --- program and shaders
    
    # Create program and shaders
    hprog = gl.glCreateProgram()
    hvert = gl.glCreateShader(gl.GL_VERTEX_SHADER)
    hfrag = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
    objects.append((gl.glDeleteProgram, hprog))
    objects.append((gl.glDeleteShader, hvert))
    objects.append((gl.glDeleteShader, hfrag))
    
    # Compile source code
    gl.glShaderSource_compat(hvert, VERT)
    gl.glShaderSource_compat(hfrag, FRAG)
    gl.glCompileShader(hvert)
    gl.glCompileShader(hfrag)
    
    # Check
    assert_equal(gl.glGetShaderInfoLog(hvert), '')
    assert_equal(gl.glGetShaderInfoLog(hfrag), '')
    assert_equal(gl.glGetShaderParameter(hvert, gl.GL_COMPILE_STATUS), 1)
    assert_equal(gl.glGetShaderParameter(hfrag, gl.GL_COMPILE_STATUS), 1)
    
    # Attach and link
    gl.glAttachShader(hprog, hvert)
    gl.glAttachShader(hprog, hfrag)
    # touch glDetachShader
    gl.glDetachShader(hprog, hvert)
    gl.glAttachShader(hprog, hvert)
    gl.glLinkProgram(hprog)
    
    # Test that indeed these shaders are attached
    attached_shaders = gl.glGetAttachedShaders(hprog)
    assert_equal(set(attached_shaders), set([hvert, hfrag]))
    
    # Check
    assert_equal(gl.glGetProgramInfoLog(hprog), '')
    assert_equal(gl.glGetProgramParameter(hprog, gl.GL_LINK_STATUS), 1)
    gl.glValidateProgram(hprog)
    assert_equal(gl.glGetProgramParameter(hprog, gl.GL_VALIDATE_STATUS), 1)
    
    # Use it!
    gl.glUseProgram(hprog)
    
    # Bind one attribute
    gl.glBindAttribLocation(hprog, 1, 'a_2')
    
    # Check if all is ok
    assert_equal(gl.glGetError(), 0)
    
    # Check source
    vert_source = gl.glGetShaderSource(hvert)
    assert_true('attribute vec2 a_2;' in vert_source)
    
    # --- get information on attributes and uniforms
    
    # Count attribbutes and uniforms
    natt = gl.glGetProgramParameter(hprog, gl.GL_ACTIVE_ATTRIBUTES)
    nuni = gl.glGetProgramParameter(hprog, gl.GL_ACTIVE_UNIFORMS)
    assert_equal(natt, 4)
    assert_equal(nuni, 4+4+3+1)
    
    # Get names
    names = {}
    for i in range(natt):
        name, count, type = gl.glGetActiveAttrib(hprog, i)
        names[name] = type
        assert_equal(count, 1)
    for i in range(nuni):
        name, count, type = gl.glGetActiveUniform(hprog, i)
        names[name] = type
        assert_equal(count, 1)
    
    # Check
    assert_equal(names['a_1'], gl.GL_FLOAT)
    assert_equal(names['a_2'], gl.GL_FLOAT_VEC2)
    assert_equal(names['a_3'], gl.GL_FLOAT_VEC3)
    assert_equal(names['a_4'], gl.GL_FLOAT_VEC4)
    assert_equal(names['s_1'], gl.GL_SAMPLER_2D)
    #
    for i, type in enumerate([gl.GL_FLOAT, gl.GL_FLOAT_VEC2, 
                              gl.GL_FLOAT_VEC3, gl.GL_FLOAT_VEC4]):
        assert_equal(names['u_f%i' % (i+1)], type)
    for i, type in enumerate([gl.GL_INT, gl.GL_INT_VEC2, 
                              gl.GL_INT_VEC3, gl.GL_INT_VEC4]):
        assert_equal(names['u_i%i' % (i+1)], type)
    for i, type in enumerate([gl.GL_FLOAT_MAT2, gl.GL_FLOAT_MAT3, 
                              gl.GL_FLOAT_MAT4]):
        assert_equal(names['u_m%i' % (i+2)], type)
    
    # Check if all is ok
    assert_equal(gl.glGetError(), 0)
    
    # --- texture
    
    # Create, bind, activate
    htex = gl.glCreateTexture()
    objects.append((gl.glDeleteTexture, htex))
    gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)
    gl.glBindTexture(gl.GL_TEXTURE_2D, htex)
    
    # Allocate data and upload
    # This data is luminance and not C-contiguous
    gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_LUMINANCE, gl.GL_LUMINANCE, 
                    gl.GL_UNSIGNED_BYTE, im2)  # touch
    gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_LUMINANCE, gl.GL_LUMINANCE, 
                    gl.GL_UNSIGNED_BYTE, im2.shape[:2])
    gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, gl.GL_LUMINANCE,
                       gl.GL_UNSIGNED_BYTE, im2)
    
    # Set texture parameters (use f and i to touch both)
    T = gl.GL_TEXTURE_2D
    gl.glTexParameterf(T, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
    gl.glTexParameteri(T, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
    
    # Re-allocate data and upload 
    gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, gl.GL_RGB, 
                    gl.GL_UNSIGNED_BYTE, im1.shape[:2])
    gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, gl.GL_RGB,
                       gl.GL_UNSIGNED_BYTE, im1)
    
    # Attach!
    loc = gl.glGetUniformLocation(hprog, 's_1')
    unit = 0
    gl.glActiveTexture(gl.GL_TEXTURE0+unit)
    gl.glUniform1i(loc, unit) 
    
    # Mipmaps (just to touch this function)
    gl.glGenerateMipmap(gl.GL_TEXTURE_2D)
    
    # Check min filter (touch getTextParameter)
    minfilt = gl.glGetTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER)
    assert_equal(minfilt, gl.GL_LINEAR)
    
    # Check if all is ok
    assert_equal(gl.glGetError(), 0)
    
    # --- buffer vec2 (contiguous VBO)
    
    # Create buffer
    hbuf2 = gl.glCreateBuffer()
    objects.append((gl.glDeleteBuffer, hbuf2))
    gl.glBindBuffer(gl.GL_ARRAY_BUFFER, hbuf2)

    # Allocate and set data
    gl.glBufferData(gl.GL_ARRAY_BUFFER, buf2.nbytes, gl.GL_DYNAMIC_DRAW)
    gl.glBufferSubData(gl.GL_ARRAY_BUFFER, 0, buf2)
    
    # Attach!
    loc = gl.glGetAttribLocation(hprog, 'a_2')
    gl.glDisableVertexAttribArray(loc)  # touch
    gl.glEnableVertexAttribArray(loc)
    gl.glVertexAttribPointer(loc, 2, gl.GL_FLOAT, False, 2*4, 0)
    
    # Check (touch glGetBufferParameter, glGetVertexAttrib and
    # glGetVertexAttribOffset)
    size = gl.glGetBufferParameter(gl.GL_ARRAY_BUFFER, gl.GL_BUFFER_SIZE)
    assert_equal(size, buf2.nbytes)
    stride = gl.glGetVertexAttrib(loc, gl.GL_VERTEX_ATTRIB_ARRAY_STRIDE)
    assert_equal(stride, 2*4)
    offset = gl.glGetVertexAttribOffset(loc, gl.GL_VERTEX_ATTRIB_ARRAY_POINTER)
    assert_equal(offset, 0)
    
    # Check if all is ok
    assert_equal(gl.glGetError(), 0)
    
    # --- buffer vec3 (non-contiguous VBO)
    
    # Create buffer
    hbuf3 = gl.glCreateBuffer()
    objects.append((gl.glDeleteBuffer, hbuf3))
    gl.glBindBuffer(gl.GL_ARRAY_BUFFER, hbuf3)

    # Allocate and set data
    gl.glBufferData(gl.GL_ARRAY_BUFFER, buf3.nbytes, gl.GL_DYNAMIC_DRAW)
    gl.glBufferSubData(gl.GL_ARRAY_BUFFER, 0, buf3)
    
    # Attach!
    loc = gl.glGetAttribLocation(hprog, 'a_3')
    gl.glEnableVertexAttribArray(loc)
    gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, 3*4, 0)
    
    # Check if all is ok
    assert_equal(gl.glGetError(), 0)
    
    # --- buffer vec4 (client vertex data)
    
    # Select no FBO
    gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
    
    # Attach!
    loc = gl.glGetAttribLocation(hprog, 'a_4')
    gl.glEnableVertexAttribArray(loc)
    gl.glVertexAttribPointer(loc, 4, gl.GL_FLOAT, False, 4*4, buf4)
    
    # Check if all is ok
    assert_equal(gl.glGetError(), 0)
    
    # --- element buffer
    
    # Create buffer
    global helements
    helements = gl.glCreateBuffer()
    objects.append((gl.glDeleteBuffer, helements))
    gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, helements)

    # Allocate and set data
    gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, elements, gl.GL_DYNAMIC_DRAW)
    gl.glBufferSubData(gl.GL_ELEMENT_ARRAY_BUFFER, 0, elements)
    
    # Turn off
    gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
    
    # Check if all is ok
    assert_equal(gl.glGetError(), 0)
    
    # --- uniforms
    
    # Set integer uniforms to 0
    # We set them twice just to touch both i and iv functions
    for i, fun1, fun2 in [(1, gl.glUniform1i, gl.glUniform1iv),
                          (2, gl.glUniform2i, gl.glUniform2iv),
                          (3, gl.glUniform3i, gl.glUniform3iv),
                          (4, gl.glUniform4i, gl.glUniform4iv)]:
        name = 'u_i%i' % i
        value = [0] * i
        loc = gl.glGetUniformLocation(hprog, name)
        fun1(loc, *value)  # e.g. glUniform4i
        fun2(loc, 1, value)  # e.g. glUniform4iv

    # Set float uniforms to 1.0
    # We set them twice just to touch both i and iv functions
    for i, fun1, fun2 in [(1, gl.glUniform1f, gl.glUniform1fv),
                          (2, gl.glUniform2f, gl.glUniform2fv),
                          (3, gl.glUniform3f, gl.glUniform3fv),
                          (4, gl.glUniform4f, gl.glUniform4fv)]:
        name = 'u_f%i' % i
        value = [1.0] * i
        loc = gl.glGetUniformLocation(hprog, name)
        fun1(loc, *value)  # e.g. glUniform4f
        fun2(loc, 1, value)  # e.g. glUniform4fv
    
    # Set matrix uniforms
    m = np.eye(5, dtype='float32')
    loc = gl.glGetUniformLocation(hprog, 'u_m2')
    gl.glUniformMatrix2fv(loc, 1, False, m[:2, :2])
    #
    loc = gl.glGetUniformLocation(hprog, 'u_m3')
    m = np.eye(3, dtype='float32')
    gl.glUniformMatrix3fv(loc, 1, False, m[:3, :3])
    #
    loc = gl.glGetUniformLocation(hprog, 'u_m4')
    m = np.eye(4, dtype='float32')
    gl.glUniformMatrix4fv(loc, 1, False, m[:4, :4])
    
    # Check some uniforms
    loc = gl.glGetUniformLocation(hprog, 'u_i1')
    assert_equal(gl.glGetUniform(hprog, loc), 0)
    loc = gl.glGetUniformLocation(hprog, 'u_i2')
    assert_equal(gl.glGetUniform(hprog, loc), (0, 0))
    loc = gl.glGetUniformLocation(hprog, 'u_f2')
    assert_equal(gl.glGetUniform(hprog, loc), (1.0, 1.0))
    
    # Check if all is ok
    assert_equal(gl.glGetError(), 0)
    
    # --- attributes 
    
    # Constant values for attributes. We do not even use this ...
    loc = gl.glGetAttribLocation(hprog, 'a_1')
    gl.glVertexAttrib1f(loc, 1.0)
    loc = gl.glGetAttribLocation(hprog, 'a_2')
    gl.glVertexAttrib2f(loc, 1.0, 1.0)
    loc = gl.glGetAttribLocation(hprog, 'a_3')
    gl.glVertexAttrib3f(loc, 1.0, 1.0, 1.0)
    loc = gl.glGetAttribLocation(hprog, 'a_4')
    gl.glVertexAttrib4f(loc, 1.0, 1.0, 1.0, 1.0)
    
    # --- flush and finish
    
    # Not really necessary, but we want to touch the functions
    gl.glFlush()
    gl.glFinish()
    
    #print([i[1] for i in objects])
    return objects
Esempio n. 4
0
def _prepare_vis():

    objects = []

    # --- program and shaders

    # Create program and shaders
    hprog = gl.glCreateProgram()
    hvert = gl.glCreateShader(gl.GL_VERTEX_SHADER)
    hfrag = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
    objects.append((gl.glDeleteProgram, hprog))
    objects.append((gl.glDeleteShader, hvert))
    objects.append((gl.glDeleteShader, hfrag))

    # Compile source code
    gl.glShaderSource(hvert, VERT)
    gl.glShaderSource(hfrag, FRAG)
    gl.glCompileShader(hvert)
    gl.glCompileShader(hfrag)

    # Check
    assert gl.glGetShaderInfoLog(hvert) == ''
    assert gl.glGetShaderInfoLog(hfrag) == ''
    assert gl.glGetShaderParameter(hvert, gl.GL_COMPILE_STATUS) == 1
    assert gl.glGetShaderParameter(hfrag, gl.GL_COMPILE_STATUS) == 1

    # Attach and link
    gl.glAttachShader(hprog, hvert)
    gl.glAttachShader(hprog, hfrag)
    # touch glDetachShader
    gl.glDetachShader(hprog, hvert)
    gl.glAttachShader(hprog, hvert)

    # Bind all attributes - we could let this occur automatically, but some
    # implementations bind an attribute to index 0, which has the unfortunate
    # property of being unable to be modified.
    gl.glBindAttribLocation(hprog, 1, 'a_1')
    gl.glBindAttribLocation(hprog, 2, 'a_2')
    gl.glBindAttribLocation(hprog, 3, 'a_3')
    gl.glBindAttribLocation(hprog, 4, 'a_4')

    gl.glLinkProgram(hprog)

    # Test that indeed these shaders are attached
    attached_shaders = gl.glGetAttachedShaders(hprog)
    assert_equal(set(attached_shaders), set([hvert, hfrag]))

    # Check
    assert_equal(gl.glGetProgramInfoLog(hprog), '')
    assert_equal(gl.glGetProgramParameter(hprog, gl.GL_LINK_STATUS), 1)
    gl.glValidateProgram(hprog)
    assert_equal(gl.glGetProgramParameter(hprog, gl.GL_VALIDATE_STATUS), 1)

    # Use it!
    gl.glUseProgram(hprog)

    # Check if all is ok
    assert_equal(gl.glGetError(), 0)

    # Check source
    vert_source = gl.glGetShaderSource(hvert)
    assert_true('attribute vec2 a_2;' in vert_source)

    # --- get information on attributes and uniforms

    # Count attributes and uniforms
    natt = gl.glGetProgramParameter(hprog, gl.GL_ACTIVE_ATTRIBUTES)
    nuni = gl.glGetProgramParameter(hprog, gl.GL_ACTIVE_UNIFORMS)
    assert_equal(natt, 4)
    assert_equal(nuni, 4+4+3+1)

    # Get names
    names = {}
    for i in range(natt):
        name, count, type = gl.glGetActiveAttrib(hprog, i)
        names[name] = type
        assert_equal(count, 1)
    for i in range(nuni):
        name, count, type = gl.glGetActiveUniform(hprog, i)
        names[name] = type
        assert_equal(count, 1)

    # Check
    assert_equal(names['a_1'], gl.GL_FLOAT)
    assert_equal(names['a_2'], gl.GL_FLOAT_VEC2)
    assert_equal(names['a_3'], gl.GL_FLOAT_VEC3)
    assert_equal(names['a_4'], gl.GL_FLOAT_VEC4)
    assert_equal(names['s_1'], gl.GL_SAMPLER_2D)
    #
    for i, type in enumerate([gl.GL_FLOAT, gl.GL_FLOAT_VEC2,
                              gl.GL_FLOAT_VEC3, gl.GL_FLOAT_VEC4]):
        assert_equal(names['u_f%i' % (i+1)], type)
    for i, type in enumerate([gl.GL_INT, gl.GL_INT_VEC2,
                              gl.GL_INT_VEC3, gl.GL_INT_VEC4]):
        assert_equal(names['u_i%i' % (i+1)], type)
    for i, type in enumerate([gl.GL_FLOAT_MAT2, gl.GL_FLOAT_MAT3,
                              gl.GL_FLOAT_MAT4]):
        assert_equal(names['u_m%i' % (i+2)], type)

    # Check if all is ok
    assert_equal(gl.glGetError(), 0)

    # --- texture

    # Create, bind, activate
    htex = gl.glCreateTexture()
    objects.append((gl.glDeleteTexture, htex))
    gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)
    gl.glBindTexture(gl.GL_TEXTURE_2D, htex)

    # Allocate data and upload
    # This data is luminance and not C-contiguous
    gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_LUMINANCE, gl.GL_LUMINANCE,
                    gl.GL_UNSIGNED_BYTE, im2)  # touch
    gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_LUMINANCE, gl.GL_LUMINANCE,
                    gl.GL_UNSIGNED_BYTE, im2.shape[:2])
    gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, gl.GL_LUMINANCE,
                       gl.GL_UNSIGNED_BYTE, im2)

    # Set texture parameters (use f and i to touch both)
    T = gl.GL_TEXTURE_2D
    gl.glTexParameterf(T, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
    gl.glTexParameteri(T, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)

    # Re-allocate data and upload
    gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, gl.GL_RGB,
                    gl.GL_UNSIGNED_BYTE, im1.shape[:2])
    gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, gl.GL_RGB,
                       gl.GL_UNSIGNED_BYTE, im1)

    # Attach!
    loc = gl.glGetUniformLocation(hprog, 's_1')
    unit = 0
    gl.glActiveTexture(gl.GL_TEXTURE0+unit)
    gl.glUniform1i(loc, unit)

    # Mipmaps (just to touch this function)
    gl.glGenerateMipmap(gl.GL_TEXTURE_2D)

    # Check min filter (touch getTextParameter)
    minfilt = gl.glGetTexParameter(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER)
    assert_equal(minfilt, gl.GL_LINEAR)

    # Check if all is ok
    assert_equal(gl.glGetError(), 0)

    # --- buffer vec2 (contiguous VBO)

    # Create buffer
    hbuf2 = gl.glCreateBuffer()
    objects.append((gl.glDeleteBuffer, hbuf2))
    gl.glBindBuffer(gl.GL_ARRAY_BUFFER, hbuf2)

    # Allocate and set data
    gl.glBufferData(gl.GL_ARRAY_BUFFER, buf2.nbytes, gl.GL_DYNAMIC_DRAW)
    gl.glBufferSubData(gl.GL_ARRAY_BUFFER, 0, buf2)

    # Attach!
    loc = gl.glGetAttribLocation(hprog, 'a_2')
    gl.glDisableVertexAttribArray(loc)  # touch
    gl.glEnableVertexAttribArray(loc)
    gl.glVertexAttribPointer(loc, 2, gl.GL_FLOAT, False, 2*4, 0)

    # Check (touch glGetBufferParameter, glGetVertexAttrib and
    # glGetVertexAttribOffset)
    size = gl.glGetBufferParameter(gl.GL_ARRAY_BUFFER, gl.GL_BUFFER_SIZE)
    assert_equal(size, buf2.nbytes)
    stride = gl.glGetVertexAttrib(loc, gl.GL_VERTEX_ATTRIB_ARRAY_STRIDE)
    assert_equal(stride, 2*4)
    offset = gl.glGetVertexAttribOffset(loc, gl.GL_VERTEX_ATTRIB_ARRAY_POINTER)
    assert_equal(offset, 0)

    # Check if all is ok
    assert_equal(gl.glGetError(), 0)

    # --- buffer vec3 (non-contiguous VBO)

    # Create buffer
    hbuf3 = gl.glCreateBuffer()
    objects.append((gl.glDeleteBuffer, hbuf3))
    gl.glBindBuffer(gl.GL_ARRAY_BUFFER, hbuf3)

    # Allocate and set data
    gl.glBufferData(gl.GL_ARRAY_BUFFER, buf3.nbytes, gl.GL_DYNAMIC_DRAW)
    gl.glBufferSubData(gl.GL_ARRAY_BUFFER, 0, buf3)

    # Attach!
    loc = gl.glGetAttribLocation(hprog, 'a_3')
    gl.glEnableVertexAttribArray(loc)
    gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, 3*4, 0)

    # Check if all is ok
    assert_equal(gl.glGetError(), 0)

    # --- buffer vec4 (client vertex data)

    # Select no FBO
    gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)

    # Attach!
    loc = gl.glGetAttribLocation(hprog, 'a_4')
    gl.glEnableVertexAttribArray(loc)
    gl.glVertexAttribPointer(loc, 4, gl.GL_FLOAT, False, 4*4, buf4)

    # Check if all is ok
    assert_equal(gl.glGetError(), 0)

    # --- element buffer

    # Create buffer
    global helements
    helements = gl.glCreateBuffer()
    objects.append((gl.glDeleteBuffer, helements))
    gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, helements)

    # Allocate and set data
    gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, elements, gl.GL_DYNAMIC_DRAW)
    gl.glBufferSubData(gl.GL_ELEMENT_ARRAY_BUFFER, 0, elements)

    # Turn off
    gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)

    # Check if all is ok
    assert_equal(gl.glGetError(), 0)

    # --- uniforms

    # Set integer uniforms to 0
    # We set them twice just to touch both i and iv functions
    for i, fun1, fun2 in [(1, gl.glUniform1i, gl.glUniform1iv),
                          (2, gl.glUniform2i, gl.glUniform2iv),
                          (3, gl.glUniform3i, gl.glUniform3iv),
                          (4, gl.glUniform4i, gl.glUniform4iv)]:
        name = 'u_i%i' % i
        value = [0] * i
        loc = gl.glGetUniformLocation(hprog, name)
        fun1(loc, *value)  # e.g. glUniform4i
        fun2(loc, 1, value)  # e.g. glUniform4iv

    # Set float uniforms to 1.0
    # We set them twice just to touch both i and iv functions
    for i, fun1, fun2 in [(1, gl.glUniform1f, gl.glUniform1fv),
                          (2, gl.glUniform2f, gl.glUniform2fv),
                          (3, gl.glUniform3f, gl.glUniform3fv),
                          (4, gl.glUniform4f, gl.glUniform4fv)]:
        name = 'u_f%i' % i
        value = [1.0] * i
        loc = gl.glGetUniformLocation(hprog, name)
        fun1(loc, *value)  # e.g. glUniform4f
        fun2(loc, 1, value)  # e.g. glUniform4fv

    # Set matrix uniforms
    m = np.eye(5, dtype='float32')
    loc = gl.glGetUniformLocation(hprog, 'u_m2')
    gl.glUniformMatrix2fv(loc, 1, False, m[:2, :2])
    #
    loc = gl.glGetUniformLocation(hprog, 'u_m3')
    m = np.eye(3, dtype='float32')
    gl.glUniformMatrix3fv(loc, 1, False, m[:3, :3])
    #
    loc = gl.glGetUniformLocation(hprog, 'u_m4')
    m = np.eye(4, dtype='float32')
    gl.glUniformMatrix4fv(loc, 1, False, m[:4, :4])

    # Check some uniforms
    loc = gl.glGetUniformLocation(hprog, 'u_i1')
    assert_equal(gl.glGetUniform(hprog, loc), 0)
    loc = gl.glGetUniformLocation(hprog, 'u_i2')
    assert_equal(gl.glGetUniform(hprog, loc), (0, 0))
    loc = gl.glGetUniformLocation(hprog, 'u_f2')
    assert_equal(gl.glGetUniform(hprog, loc), (1.0, 1.0))

    # Check if all is ok
    assert_equal(gl.glGetError(), 0)

    # --- attributes

    # Constant values for attributes. We do not even use this ...
    loc = gl.glGetAttribLocation(hprog, 'a_1')
    gl.glVertexAttrib1f(loc, 1.0)
    loc = gl.glGetAttribLocation(hprog, 'a_2')
    gl.glVertexAttrib2f(loc, 1.0, 1.0)
    loc = gl.glGetAttribLocation(hprog, 'a_3')
    gl.glVertexAttrib3f(loc, 1.0, 1.0, 1.0)
    loc = gl.glGetAttribLocation(hprog, 'a_4')
    gl.glVertexAttrib4f(loc, 1.0, 1.0, 1.0, 1.0)

    # --- flush and finish

    # Not really necessary, but we want to touch the functions
    gl.glFlush()
    gl.glFinish()

    # print([i[1] for i in objects])
    return objects
    def draw(self):
        for i in range(4):
            if self._bufXglsl[i]:
                fragment = fragment_template % self._bufXglsl[i]
                self._bufXglsl[i] = None
                frag_handle = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
                gl.glShaderSource(frag_handle, fragment)
                gl.glCompileShader(frag_handle)
                status = gl.glGetShaderParameter(frag_handle,
                                        gl.GL_COMPILE_STATUS)
                if not status:
                    errors = gl.glGetShaderInfoLog(frag_handle)
                    errors = self.process_errors(errors)
                    print('Shader failed to compile:', file=sys.stderr)
                    print(errors, file=sys.stderr)
                    exit(1)
                else:
                    self._BufX[i].set_shaders(vertex, fragment)
                gl.glDeleteShader(frag_handle)
            
        if self._glsl:
            fragment = fragment_template % self._glsl
            self._glsl = None

            # Check to see if the shader will compile successfully before we
            # set it. We do this here because the ShaderWatcher runs in a
            # different thread and so can't access the GL context.

            frag_handle = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
            gl.glShaderSource(frag_handle, fragment)
            gl.glCompileShader(frag_handle)
            status = gl.glGetShaderParameter(frag_handle,
                    gl.GL_COMPILE_STATUS)
            if not status:
                errors = gl.glGetShaderInfoLog(frag_handle)
                errors = self.process_errors(errors)
                print('Shader failed to compile:', file=sys.stderr)
                print(errors, file=sys.stderr)
                exit(1)
                
                # Switch to error shader

                self._glsl = error_shader
                self.update()
            else:
                self.program.set_shaders(vertex, fragment)
            gl.glDeleteShader(frag_handle)

        if self._interactive:
            for i in range(4):
                with self._fboX[self._doubleFboid][i]:
                    gloo.set_clear_color((0.0, 0.0, 0.0, 0.0))
                    gloo.clear(color=True, depth=True)
                    gloo.set_viewport(0, 0, *self.physical_size)
                    self._BufX[i].draw()
            
            self.program.draw()

            if self._ffmpeg_pipe is not None:
                img = _screenshot()
                self.write_video_frame(img)

            self._render_frame_index += 1
            if self._render_frame_count is not None \
                and self._render_frame_index \
                >= self._render_frame_count:
                app.quit()
                return

            self._doubleFbo = not self._doubleFbo
            self._doubleFboid=(0 if self._doubleFbo else 1)
            self.advance_time()
            self.program['iFrame'] = self._render_frame_index
            self.set_Buf_uniform('iFrame' , self._render_frame_index)
            self.set_channel_input()
            self.set_Buf_channel_input()
        else:
            for i in range(4):
                with self._fboX[self._doubleFboid][i]:
                    gloo.set_clear_color((0.0, 0.0, 0.0, 0.0))
                    gloo.clear(color=True, depth=True)
                    gloo.set_viewport(0, 0, *self.physical_size)
                    self._BufX[i].draw()
                    
            with self._fbo:
                rs = list(self._render_size)

                if self._tile_coord[0] + rs[0] > self._output_size[0]:
                    rs[0] = self._output_size[0] - self._tile_coord[0]

                if self._tile_coord[1] + rs[1] > self._output_size[1]:
                    rs[1] = self._output_size[1] - self._tile_coord[1]

                gloo.set_viewport(0, 0, *rs)
                self.program['iOffset'] = self._tile_coord
                self.program.draw()
                self._doubleFbo = not self._doubleFbo
                self._doubleFboid=(0 if self._doubleFbo else 1)
                self.program['iFrame'] = self._render_frame_index
                self.set_Buf_uniform('iFrame' , self._render_frame_index)
                self.set_channel_input()
                self.set_Buf_channel_input()
                img = _screenshot()
                row = self._output_size[1] - self._tile_coord[1] - rs[1]
                col = self._tile_coord[0]
                self._img[row:row + rs[1], col:col + rs[0], :] = img