compute
FreeBodyEngine.graphics.webgl.compute
#
The WebGL2 "compute" backend: same fullscreen-fragment-pass emulation as
graphics/gl33/compute.py (WebGL2, like GL 3.3, has no glDispatchCompute/
SSBOs/image-load-store either) - one output pixel per logical invocation,
inputs read via buffer-texture-emulated texelFetch (see graphics/webgl/
buffer.py's WebGL2TextureBuffer and graphics/webgl/generator.py's
buffer-block/raytrace codegen for why that's a 2D data texture here rather
than a real GL_TEXTURE_BUFFER), outputs written to float framebuffer
attachments. Mirrors GLComputeShader/GLRaytraceShader class-for-class and
method-for-method - the only real differences throughout are mechanical:
PyOpenGL's glFoo(...) global-state calls become self.gl.foo(...) calls
against this canvas's WebGL2RenderingContext, same as every other
graphics/webgl/*.py module (see shader.py's own docstring).
GLSL_OUTPUT_FORMAT = {'float': AttachmentFormat.R32F, 'vec2': AttachmentFormat.RG32F, 'vec4': AttachmentFormat.RGBA32F}
module-attribute
#
WebGL2ComputeShader(source, injector=None, shader_type=ShaderType.COMPUTE)
#
Bases: ComputeShader
The WebGL2 implementation of ComputeShader. Fulfills the abstract dispatch()/bind_buffer()/set_uniform()/read_output()/get_output_texture()/ blit_to_screen() contract entirely through the fullscreen-fragment-pass emulation described in this module's docstring, since WebGL2 has no real compute shaders to compile against.
Compiles source via WebGL2Generator into a fragment shader,
links it against the shared attributeless _FULLSCREEN_VERT_SRC
vertex shader, and introspects the resulting program's active
uniforms. Also regex-scans the generated fragment source for its
out <type> <name>; declarations (see _OUTPUT_DECL_RE) to learn
each @output field's name and GLSL type up front, since
dispatch() needs that to build the matching framebuffer
attachments later.
gl = get_service('renderer').gl
instance-attribute
#
shader_type = shader_type
instance-attribute
#
uniforms = {}
instance-attribute
#
bind_buffer(block, field, buffer)
#
Binds buffer to the field of a buffer <block>: block
declared in the kernel's source (the GLSL uniform this lowers to
is named _ENGINE_<block>_<field>, matching
WebGL2Generator.generate_buffer_block()).
bind_texture(uniform_name, texture)
#
Binds an ordinary 2D Texture (e.g. one wrapping a rasterized
G-buffer attachment via TextureManager.wrap_external_texture) to a
texture-typed @uniform in this kernel's source, so it can be
read with the sample()/fb_sample() builtin - the same binding
an ordinary shader's Material.use() does (see
WebGL2Shader._bind_textures), just invoked directly rather than
driven by material property data.
Deliberately does NOT go through TextureManager.bind_texture()/
_allocate_slot() - see GLComputeShader.bind_texture()'s own
docstring for exactly why (this kernel's own _next_unit/
_buffer_units counter needs to stay independent of whatever the
ordinary draw-call texture manager is doing for other shaders,
the same reasoning applies unchanged on this backend).
blit_to_screen(name, size=None)
#
Blits one @output field's result directly to whatever framebuffer is currently bound (the screen, if nothing else is bound) - the simplest way to show a compute/raytrace result on screen without wrapping it in a Sprite/Material. Mirrors WebGL2Framebuffer.draw(), which the rest of the engine already uses for showing a G-buffer channel.
destroy()
#
Releases every WebGL2TextureBuffer this kernel bound (via
bind_buffer()/upload_scene()) and deletes the underlying GL
program. Does not delete the shared _empty_vao (class-level,
reused across every WebGL2ComputeShader instance) or the backing
FBO's own GL objects.
dispatch(width, height)
#
Emulates one dispatch over a width x height logical
invocation grid as a single fullscreen draw - see
GLComputeShader.dispatch()'s own docstring for the full mechanism,
identical here down to the shared attributeless VAO trick, just
issued through self.gl instead of PyOpenGL's global-state
calls.
get_output_texture(name)
#
Wraps the @output field name's backing color attachment as
an ordinary Texture (via TextureManager.wrap_external_texture), so
a compute/raytrace result can flow into the normal material/sprite
pipeline without a CPU readback. Requires dispatch() to have
already run at least once, since that's what creates the FBO.
read_output(name)
#
Synchronously reads back the @output field name's results via
the backing FBO's read() (a GPU->CPU stall - see
WebGL2Framebuffer.read). Requires dispatch() to have already run
at least once, since that's what creates the FBO.
set_uniform(name, value)
#
Sets uniform name on this kernel's program to value, via the
same set_gl_uniform() type-dispatch table WebGL2Shader.set_uniform()
uses. Warns instead of raising if name isn't an active uniform.
WebGL2RaytraceShader(source, injector=None)
#
Bases: WebGL2ComputeShader
A @raytrace kernel: the same fullscreen-pass dispatch mechanism as
WebGL2ComputeShader, plus scene data (a BVH and its triangles) uploaded
as buffer-texture-emulated 2D data textures for the generated
trace_ray() to walk. See graphics/raytrace/bvh.py for the CPU-side
BVH builder that produces bvh_aabb/bvh_meta in the layout this
expects - identical to GLRaytraceShader's own contract, just backed by
WebGL2TextureBuffer instead of TextureBuffer.
Compiles source as a RAYTRACE-stage kernel (so WebGL2Generator
emits the trace_ray()/make_ray()/etc. intrinsics), leaving the
scene buffer slots unset until upload_scene() fills them in.
upload_scene(bvh_aabb, bvh_meta, triangles)
#
bvh_aabb: (num_nodes2, 4) float32. bvh_meta: (num_nodes, 4)
int32 (left_child, right_child, first_prim, prim_count).
triangles: (num_triangles, 3, 3) or (num_triangles3, 3) float32
vertex positions, in the order bvh_meta's (first_prim,
prim_count) ranges index into - i.e. already reordered by the BVH
builder, not the original input order. Same contract as
GLRaytraceShader.upload_scene().