Skip to content

Instantly share code, notes, and snippets.

@aforren1
Last active November 24, 2021 12:35
Show Gist options
  • Select an option

  • Save aforren1/a590b994e4b2ba7e40c6aa965bd0bbca to your computer and use it in GitHub Desktop.

Select an option

Save aforren1/a590b994e4b2ba7e40c6aa965bd0bbca to your computer and use it in GitHub Desktop.
import moderngl as mgl
import glfw
import numpy as np
import glm
import mapbox_earcut as earcut
from timeit import default_timer
from xxhash import xxh32
vao_cache = {}
class Shape:
def __init__(self, ctx, shader, vertices, pos=(0, 0), color=(0,0,0,1), name=None):
self.color = glm.vec4(color)
self.pos = glm.vec2(pos)
self.name = name
idx = earcut.triangulate_float32(vertices, [vertices.shape[0]])
foo = vertices[idx]
hsh = xxh32(seed=1)
hsh.update(foo.data)
hsh.update(shader.glo.to_bytes(4, 'big'))
digest = hsh.hexdigest()
if digest not in vao_cache:
buf = ctx.buffer(data=foo)
self.vao = vao_cache[digest] = ctx.vertex_array(shader, buf, 'vert')
else:
self.vao = vao_cache[digest]
self.offset_unif = shader['offset']
self.color_unif = shader['color']
def draw(self):
self.offset_unif.write(self.pos)
self.color_unif.write(self.color)
self.vao.render(mgl.TRIANGLES)
vert = '''
#version 450
layout(location = 0) in vec2 vert;
uniform vec2 offset;
void main() {
gl_Position = vec4(vert + offset, 0.0, 1.0);
}
'''
frag = '''
#version 450
layout(location = 0) uniform vec4 color;
layout(location = 0) out vec4 out_color;
void main() {
out_color = color;
}
'''
frag2 = '''
#version 450
layout(location = 0) uniform vec4 color;
layout(location = 0) out vec4 out_color;
void main() {
out_color = color;
out_color.rgb = out_color.brg;
}
'''
rect = np.array([[-1, -1], [1, -1], [1, 1], [-1, 1]], dtype='f4') * 0.02
cross = np.array([[-1, 0.2], [-0.2, 0.2], [-0.2, 1], [0.2, 1],
[0.2, 0.2], [1, 0.2], [1, -0.2], [0.2, -0.2],
[0.2, -1], [-0.2, -1], [-0.2, -0.2], [-1, -0.2]], dtype='f4') * 0.02
arrow = np.array([[-1, 0.4], [0, 0.4], [0, 0.8], [1, 0],
[0, -0.8], [0, -0.4], [-1, -0.4]], dtype='f4') * 0.02
def prod(x, y):
return np.dstack(np.meshgrid(x, y)).reshape(-1, 2)
if __name__ == '__main__':
import sys
if not glfw.init():
raise RuntimeError('GLFW failed.')
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 5)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True)
glfw.window_hint(glfw.VISIBLE, True)
if not (win := glfw.create_window(600, 600, 'Test', None, None)):
glfw.terminate()
raise RuntimeError('Window failed.')
glfw.make_context_current(win)
glfw.swap_interval(1)
ctx = mgl.create_context(require=450)
prog = ctx.program(vertex_shader=vert, fragment_shader=frag)
prog2 = ctx.program(vertex_shader=vert, fragment_shader=frag2)
bs = np.linspace(-1, 1, 50)
shps = []
prods = prod(bs, bs)
tot = prods.shape[0]
bufs = [rect, cross, arrow]
names = [0, 1, 2]
t0 = default_timer()
for i, (x, y) in enumerate(prods):
col = i / tot, x * 0.5 + 0.5, y * 0.5 + 0.5, 1
p = prog if y > 0 else prog2
shps.append(Shape(ctx, p, bufs[i % 3], pos=(x, y), color=col, name=names[i % 3]))
print(f'Startup time: {default_timer() - t0}')
if len(sys.argv) > 1 and sys.argv[1] == '-sort':
shps.sort(key=lambda x: x.name, reverse=True)
query = ctx.query(time=True)
N_SAMPLES = 1000
cpu_times = np.empty(N_SAMPLES)
gpu_times = np.empty(N_SAMPLES)
counter = 0
while not glfw.window_should_close(win) and counter < N_SAMPLES:
ctx.clear(0.2, 0.1, 0.1)
with query:
t0 = default_timer()
for shp in shps:
shp.draw()
#vao.render()
t1 = default_timer()
cpu_times[counter] = t1 - t0
gpu_times[counter] = query.elapsed
glfw.swap_buffers(win)
glfw.poll_events()
counter += 1
glfw.terminate()
print(f'Avg CPU: {np.mean(cpu_times) * 1000} ms')
print(f'Avg GPU: {np.mean(gpu_times) / 1000000} ms')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment