def _path_scene(cfg, path, points=None, controls=None, easing="linear"): cfg.aspect_ratio = (1, 1) anim_kf = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, 1, easing), ] geom = ngl.Circle(radius=0.03, npoints=32) shape = ngl.RenderColor(COLORS.orange, geometry=geom) moving_shape = ngl.Translate(shape, vector=ngl.AnimatedPath(anim_kf, path)) objects = [] if points: debug_points = {f"P{i}": p[:2] for i, p in enumerate(points)} objects.append(get_debug_points(cfg, debug_points)) if controls: debug_controls = {f"C{i}": p[:2] for i, p in enumerate(controls)} objects.append(get_debug_points(cfg, debug_controls, color=COLORS.cyan)) objects.append(moving_shape) return ngl.Group(children=objects)
def texture_mipmap(cfg, show_dbg_points=False): cfg.aspect_ratio = (1, 1) cuepoints = _get_texture_mipmap_cuepoints() black = (0, 0, 0, 255) white = (255, 255, 255, 255) p = _N // 2 cb_data = array.array( 'B', ((black + white) * p + (white + black) * p) * p, ) cb_buffer = ngl.BufferUBVec4(data=cb_data) texture = ngl.Texture2D( width=_N, height=_N, min_filter='nearest', mipmap_filter='linear', data_src=cb_buffer, ) program = ngl.Program(vertex=_RENDER_TEXTURE_LOD_VERT, fragment=_RENDER_TEXTURE_LOD_FRAG) program.update_vert_out_vars(var_uvcoord=ngl.IOVec2()) quad = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) render = ngl.Render(quad, program) render.update_frag_resources(tex0=texture) group = ngl.Group(children=(render, )) if show_dbg_points: group.add_children(get_debug_points(cfg, cuepoints)) return group
def _get_live_shared_uniform_with_block_scene(cfg, color, layout, debug_positions): vertex = ''' void main() { ngl_out_pos = ngl_projection_matrix * ngl_modelview_matrix * ngl_position; } ''' fragment = ''' void main() { ngl_out_color = data.color; } ''' program = ngl.Program(vertex=vertex, fragment=fragment) group = ngl.Group() for i in range(2): block = ngl.Block(fields=[color], layout=layout) quad = ngl.Quad((-1 + i, -1 + i, 0), (1, 0, 0), (0, 1, 0)) render = ngl.Render(quad, program) render.update_frag_resources(data=block) group.add_children(render) if debug_positions: group.add_children(get_debug_points(cfg, _SHARED_UNIFORM_CUEPOINTS)) return group
def texture_mipmap(cfg, show_dbg_points=False): cfg.aspect_ratio = (1, 1) cuepoints = _get_texture_mipmap_cuepoints() black = (0, 0, 0, 255) white = (255, 255, 255, 255) p = _N // 2 cb_data = array.array( 'B', ((black + white) * p + (white + black) * p) * p, ) cb_buffer = ngl.BufferUBVec4(data=cb_data) texture = ngl.Texture2D( width=_N, height=_N, min_filter='nearest', mipmap_filter='linear', data_src=cb_buffer, ) shader_version = '300 es' if cfg.backend == 'gles' else '330' program = ngl.Program( vertex=_RENDER_TEXTURE_LOD_VERT % dict(version=shader_version), fragment=_RENDER_TEXTURE_LOD_FRAG % dict(version=shader_version), ) quad = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) render = ngl.Render(quad, program) render.update_textures(tex0=texture) group = ngl.Group(children=(render, )) if show_dbg_points: group.add_children(get_debug_points(cfg, cuepoints)) return group
def _get_live_shared_uniform_scene(cfg, color, debug_positions): group = ngl.Group() for i in range(2): quad = ngl.Quad((-1 + i, -1 + i, 0), (1, 0, 0), (0, 1, 0)) render = ngl.RenderColor(color, geometry=quad) group.add_children(render) if debug_positions: group.add_children(get_debug_points(cfg, _SHARED_UNIFORM_CUEPOINTS)) return group
def get_render(cfg, quad, fields, block_definition, color_definition, block_fields, color_fields, layout, debug_positions=False): func_calls = [] func_definitions = [] for i, field in enumerate(fields): field_len = field.get('len') func_calls.append('get_color_{}(w, h, 0.0, {:f} * h)'.format( field['name'], i)) func_definitions.append( _get_display_glsl_func(layout, field['name'], field['type'], field_len=field_len)) frag_data = dict( func_definitions='\n'.join(func_definitions), func_calls=' + '.join(func_calls), ) fragment = _FIELDS_FRAG % frag_data vertex = _FIELDS_VERT program = ngl.Program(vertex=vertex, fragment=fragment) program.update_vert_out_vars(var_uvcoord=ngl.IOVec2()) render = ngl.Render(quad, program) if isinstance(color_fields, dict): assert isinstance(block_fields, dict) field_names = {f['name'] for f in fields} d = {} d.update(('color_' + n, u) for (n, u) in color_fields.items() if n in field_names) d.update(('field_' + n, u) for (n, u) in block_fields.items() if n in field_names) render.update_frag_resources(**d) else: render.update_frag_resources(fields=block_fields, colors=color_fields) render.update_frag_resources(nb_fields=ngl.UniformInt(len(fields))) if debug_positions: debug_points = _get_debug_positions_from_fields(fields) dbg_circles = get_debug_points(cfg, debug_points, text_size=(.2, .1)) g = ngl.Group(children=(render, dbg_circles)) return g return render
def _get_data_streamed_buffer_vec4_scene(cfg, scale, show_dbg_points): duration = _N cfg.duration = duration * scale cfg.aspect_ratio = (1, 1) size, data_size, = _N, _N * _N time_anim = None if scale != 1: kfs = [ ngl.AnimKeyFrameFloat(0, 0), ngl.AnimKeyFrameFloat(cfg.duration, duration), ] time_anim = ngl.AnimatedTime(kfs) pts_data = array.array('q') assert pts_data.itemsize == 8 for i in range(duration): offset = 10000 if i == 0 else 0 pts_data.extend([i * 1000000 + offset]) vec4_data = array.array('f') for i in range(duration): for j in range(data_size): v = i / float(duration) + j / float(data_size * duration) vec4_data.extend([v, v, v, v]) pts_buffer = ngl.BufferInt64(data=pts_data) vec4_buffer = ngl.BufferVec4(data=vec4_data) streamed_buffer = ngl.StreamedBufferVec4(data_size, pts_buffer, vec4_buffer, time_anim=time_anim, label='data') streamed_block = ngl.Block(layout='std140', label='streamed_block', fields=(streamed_buffer, )) shader_params = dict(data_size=data_size, size=size) quad = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) program = ngl.Program( vertex=_RENDER_STREAMEDBUFFER_VERT, fragment=_RENDER_STREAMEDBUFFER_FRAG % shader_params, ) program.update_vert_out_vars(var_uvcoord=ngl.IOVec2()) render = ngl.Render(quad, program) render.update_frag_resources(streamed=streamed_block) group = ngl.Group(children=(render, )) if show_dbg_points: cuepoints = _get_data_streamed_buffer_cuepoints() group.add_children(get_debug_points(cfg, cuepoints)) return group
def _get_live_shared_uniform_scene(cfg, color, debug_positions): program = ngl.Program(vertex=cfg.get_vert('color'), fragment=cfg.get_frag('color')) group = ngl.Group() for i in range(2): quad = ngl.Quad((-1 + i, -1 + i, 0), (1, 0, 0), (0, 1, 0)) render = ngl.Render(quad, program) render.update_frag_resources(color=color) group.add_children(render) if debug_positions: group.add_children(get_debug_points(cfg, _SHARED_UNIFORM_CUEPOINTS)) return group
def _debug_overlay(cfg, scene, grid_names, show_dbg_points=False, show_labels=False): if not show_dbg_points and not show_labels: return scene assert grid_names is not None text_height = 0.25 overlay = ngl.Group() if show_labels: text_group = ngl.Group() ag = AutoGrid(grid_names) for grid_name, _, col, row in ag: text = ngl.Text( grid_name, fg_color=COLORS.white, bg_opacity=1, valign="top", box_width=(2.0, 0, 0), box_height=(0, text_height, 0), box_corner=(-1, 1.0 - text_height, 0), ) text = ag.place_node(text, (col, row)) text_group.add_children(text) scene = ngl.Translate(scene, (0, -text_height / 2.0 * ag.scale, 0), label="text offsetting") overlay.add_children(scene, text_group) else: overlay.add_children(scene) if show_dbg_points: nb = len(grid_names) dbg_positions = _get_dbg_positions(nb) if show_labels: dbg_positions = { name: (p[0], p[1] - text_height / 2.0 * ag.scale) for name, p in dbg_positions.items() } dbg_points = get_debug_points(cfg, dbg_positions, radius=0.01, text_size=(0.08, 0.08)) overlay.add_children(dbg_points) return overlay
def get_render(cfg, quad, fields, block_definition, color_definition, block_fields, color_fields, layout, debug_positions=False): func_calls = [] func_definitions = [] for i, field in enumerate(fields): is_array = 'len' in field func_calls.append('get_color_%s(w, h, 0.0, %f * h)' % (field['name'], i)) func_definitions.append(_get_display_glsl_func(layout, field['name'], field['type'], is_array=is_array)) frag_data = dict( block_definition=_get_glsl_fields_definition(1, layout, 'fields', block_definition), color_definition=_get_glsl_fields_definition(2, layout, 'colors', color_definition), layout=layout, func_definitions='\n'.join(func_definitions), func_calls=' + '.join(func_calls), ) if layout == 'std430': shader_version = '310 es' if cfg.backend == 'gles' else '430' else: shader_version = '300 es' if cfg.backend == 'gles' else '330' header = '#version %s\n' % shader_version fragment = header + _FIELDS_FRAG % frag_data vertex = header + _FIELDS_VERT program = ngl.Program(vertex=vertex, fragment=fragment) render = ngl.Render(quad, program) if isinstance(color_fields, dict): assert isinstance(block_fields, dict) field_names = set(f['name'] for f in fields) d = {} d.update(('color_' + n, u) for (n, u) in color_fields.items() if n in field_names) d.update(('field_' + n, u) for (n, u) in block_fields.items() if n in field_names) render.update_uniforms(**d) else: render.update_blocks(fields_block=block_fields, colors_block=color_fields) render.update_uniforms(nb_fields=ngl.UniformInt(len(fields))) if debug_positions: debug_points = _get_debug_positions_from_fields(fields) dbg_circles = get_debug_points(cfg, debug_points, text_size=(.2, .1)) g = ngl.Group(children=(render, dbg_circles)) return g return render
def compute_image_load_store(cfg, show_dbg_points=False): size = _N texture_data = ngl.BufferFloat( data=array.array("f", [x / (size**2) for x in range(size**2)])) texture_r = ngl.Texture2D(format="r32_sfloat", width=size, height=size, data_src=texture_data) texture_g = ngl.Texture2D(format="r32_sfloat", width=size, height=size, data_src=texture_data) texture_b = ngl.Texture2D(format="r32_sfloat", width=size, height=size, data_src=texture_data) scale = ngl.Block( fields=[ngl.UniformVec2(value=(-1.0, 1.0), label="factors")], layout="std140", ) texture_rgba = ngl.Texture2D(width=size, height=size) program = ngl.ComputeProgram(_IMAGE_LOAD_STORE_COMPUTE, workgroup_size=(size, size, 1)) program.update_properties( texture_r=ngl.ResourceProps(as_image=True), texture_g=ngl.ResourceProps(as_image=True), texture_b=ngl.ResourceProps(as_image=True), texture_rgba=ngl.ResourceProps(as_image=True, writable=True), ) compute = ngl.Compute(workgroup_count=(1, 1, 1), program=program) compute.update_resources(texture_r=texture_r, texture_g=texture_g, texture_b=texture_b, scale=scale, texture_rgba=texture_rgba) render = ngl.RenderTexture(texture_rgba) group = ngl.Group(children=(compute, render)) if show_dbg_points: cuepoints = _get_compute_histogram_cuepoints() group.add_children(get_debug_points(cfg, cuepoints)) return group
def compute_histogram(cfg, show_dbg_points=False): cfg.duration = 10 cfg.aspect_ratio = (1, 1) hsize, size, local_size = _N * _N, _N, _N // 2 data = array.array("f") for i in range(size * size): data.extend(( cfg.rng.uniform(0.0, 0.5), cfg.rng.uniform(0.25, 0.75), cfg.rng.uniform(0.5, 1.0), 1.0, )) texture_buffer = ngl.BufferVec4(data=data) texture = ngl.Texture2D(width=size, height=size, data_src=texture_buffer) texture.set_format("r32g32b32a32_sfloat") histogram_block = ngl.Block(layout="std140", label="histogram") histogram_block.add_fields( ngl.BufferUInt(hsize, label="r"), ngl.BufferUInt(hsize, label="g"), ngl.BufferUInt(hsize, label="b"), ngl.UniformUIVec3(label="max"), ) shader_params = dict(hsize=hsize, size=size, local_size=local_size) group_size = hsize // local_size clear_histogram_shader = _COMPUTE_HISTOGRAM_CLEAR % shader_params clear_histogram_program = ngl.ComputeProgram(clear_histogram_shader, workgroup_size=(local_size, 1, 1)) clear_histogram_program.update_properties(hist=ngl.ResourceProps( writable=True)) clear_histogram = ngl.Compute( workgroup_count=(group_size, 1, 1), program=clear_histogram_program, label="clear_histogram", ) clear_histogram.update_resources(hist=histogram_block) group_size = size // local_size exec_histogram_shader = _COMPUTE_HISTOGRAM_EXEC % shader_params exec_histogram_program = ngl.ComputeProgram(exec_histogram_shader, workgroup_size=(local_size, local_size, 1)) exec_histogram_program.update_properties(hist=ngl.ResourceProps( writable=True)) exec_histogram = ngl.Compute(workgroup_count=(group_size, group_size, 1), program=exec_histogram_program, label="compute_histogram") exec_histogram.update_resources(hist=histogram_block, source=texture) exec_histogram_program.update_properties(source=ngl.ResourceProps( as_image=True)) quad = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) program = ngl.Program( vertex=_RENDER_HISTOGRAM_VERT, fragment=_RENDER_HISTOGRAM_FRAG % shader_params, ) program.update_vert_out_vars(var_uvcoord=ngl.IOVec2()) render = ngl.Render(quad, program, label="render_histogram") render.update_frag_resources(hist=histogram_block) group = ngl.Group(children=(clear_histogram, exec_histogram, render)) if show_dbg_points: cuepoints = _get_compute_histogram_cuepoints() group.add_children(get_debug_points(cfg, cuepoints)) return group
def get_field_scene(cfg, spec, category, field_type, seed, debug_positions, layout, color_tint): """ Build a scene testing that a given data has been properly uploaded to the GPU memory. - `spec` contains all the fields that should also be declared (either in a block or as uniforms). All the fields are shuffled such that the field we are testing is always in a random position. This makes sure that we get the data alignment right. - `category` and `field_type` are filters in the spec to select the field(s) from which we want to read the data - `seed` is used to control the fields shuffling - `debug_positions` controls whether there are debug circles in the scene in order to make sure we are reading back the data colors at the appropriate position - `layout` controls the block layout or whether we are working with uniforms - `color_tint` is a debug helper to give a different color for each field (because if they have the same data, it is hard to indiscriminate them). """ cfg.aspect_ratio = (1, 1) # Seed only defines the random for the position of the fields fields_pos = random.Random(seed).sample(range(len(spec)), len(spec)) # Always the same colors whatever the user seed clr_rng = random.Random(0) fields_info = [] for i, field_info in enumerate(spec): create_func = field_info.get("func") if create_func is None: create_func = _FUNCS["{category}_{type}".format(**field_info)] node = create_func(field_info.get("data")) node.set_label(field_info["name"]) field_info["node"] = node if color_tint: hue = clr_rng.uniform(0, 1) field_info["color"] = colorsys.hls_to_rgb(hue, 0.6, 1.0) else: field_info["color"] = (1, 1, 1) fields_info.append(field_info) shuf_fields = [fields_info[pos] for pos in fields_pos] color_fields = [(f["name"], ngl.UniformVec3(f["color"], label=f["name"])) for f in fields_info] block_fields = [(f["name"], f["node"]) for f in shuf_fields] if layout == "uniform": color_fields = dict(color_fields) block_fields = dict(block_fields) else: color_fields = ngl.Block(fields=[f for n, f in color_fields], layout=layout, label="colors_block") block_fields = ngl.Block(fields=[f for n, f in block_fields], layout=layout, label="fields_block") fields = match_fields(fields_info, category, field_type) func_calls = [] func_definitions = [] for i, field in enumerate(fields): field_len = field.get("len") func_calls.append("get_color_{}(w, h, 0.0, {:f} * h)".format( field["name"], i)) func_definitions.append( _get_display_glsl_func(layout, field["name"], field["type"], field_len=field_len)) frag_data = dict( func_definitions="\n".join(func_definitions), func_calls=" + ".join(func_calls), ) fragment = _FIELDS_FRAG % frag_data vertex = _FIELDS_VERT program = ngl.Program(vertex=vertex, fragment=fragment) program.update_vert_out_vars(var_uvcoord=ngl.IOVec2()) quad = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) render = ngl.Render(quad, program) if isinstance(color_fields, dict): assert isinstance(block_fields, dict) field_names = {f["name"] for f in fields} d = {} d.update(("color_" + n, u) for (n, u) in color_fields.items() if n in field_names) d.update(("field_" + n, u) for (n, u) in block_fields.items() if n in field_names) render.update_frag_resources(**d) else: render.update_frag_resources(fields=block_fields, colors=color_fields) render.update_frag_resources(nb_fields=ngl.UniformInt(len(fields))) if debug_positions: debug_points = get_data_debug_positions(fields) dbg_circles = get_debug_points(cfg, debug_points, text_size=(0.2, 0.1)) g = ngl.Group(children=(render, dbg_circles)) return g return render
def compute_histogram(cfg, show_dbg_points=False): random.seed(0) cfg.duration = 10 cfg.aspect_ratio = (1, 1) hsize, size, local_size = _N * _N, _N, _N // 2 data = array.array('f') for i in range(size * size): data.extend(( random.uniform(0.0, 0.5), random.uniform(0.25, 0.75), random.uniform(0.5, 1.0), 1.0, )) texture_buffer = ngl.BufferVec4(data=data) texture = ngl.Texture2D(width=size, height=size, data_src=texture_buffer) histogram_block = ngl.Block(layout='std430', label='histogram') histogram_block.add_fields( ngl.BufferUInt(hsize), ngl.BufferUInt(hsize), ngl.BufferUInt(hsize), ngl.UniformUIVec3(), ) shader_version = '310 es' if cfg.backend == 'gles' else '430' shader_header = '#version %s\n' % shader_version if cfg.backend == 'gles' and cfg.system == 'Android': shader_header += '#extension GL_ANDROID_extension_pack_es31a: require\n' shader_params = dict(hsize=hsize, size=size, local_size=local_size) group_size = hsize // local_size clear_histogram_shader = _COMPUTE_HISTOGRAM_CLEAR % shader_params clear_histogram_program = ngl.ComputeProgram(shader_header + clear_histogram_shader) clear_histogram = ngl.Compute( group_size, 1, 1, clear_histogram_program, label='clear_histogram', ) clear_histogram.update_blocks(histogram=histogram_block) group_size = size // local_size exec_histogram_shader = _COMPUTE_HISTOGRAM_EXEC % shader_params exec_histogram_program = ngl.ComputeProgram(shader_header + exec_histogram_shader) exec_histogram = ngl.Compute( group_size, group_size, 1, exec_histogram_program, label='compute_histogram' ) exec_histogram.update_blocks(histogram=histogram_block) exec_histogram.update_textures(source=texture) quad = ngl.Quad((-1, -1, 0), (2, 0, 0), (0, 2, 0)) program = ngl.Program( vertex=shader_header + _RENDER_HISTOGRAM_VERT, fragment=shader_header + _RENDER_HISTOGRAM_FRAG % shader_params, ) render = ngl.Render(quad, program, label='render_histogram') render.update_blocks(histogram=histogram_block) group = ngl.Group(children=(clear_histogram, exec_histogram, render,)) if show_dbg_points: cuepoints = _get_compute_histogram_cuepoints() group.add_children(get_debug_points(cfg, cuepoints)) return group