Skip to content

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().