Skip to content

compute

FreeBodyEngine.graphics.gl33.compute #

The GL33 "compute" backend: since GL 3.3 has no glDispatchCompute/SSBOs/ image-load-store, a dispatch is emulated as a single fullscreen draw through the fixed vertex+fragment pipeline - one output pixel (one draw of the fullscreen triangle, rasterized to a width x height viewport) per logical invocation. Inputs are buffer blocks read via buffer-texture texelFetch; outputs are @output fields written to float framebuffer attachments (see FreeBodyEngine.graphics.gl33.generator.GL33Generator and its CAPABILITIES for exactly what this backend can and can't express).

GLSL_OUTPUT_FORMAT = {'float': AttachmentFormat.R32F, 'vec2': AttachmentFormat.RG32F, 'vec4': AttachmentFormat.RGBA32F} module-attribute #

GLComputeShader(source, injector=None, shader_type=ShaderType.COMPUTE) #

Bases: ComputeShader

The GL 3.3 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 GL 3.3 has no real compute shaders to compile against.

Compiles source via GL33Generator 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.

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 GL33Generator.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() builtin - the same binding a regular fragment shader's Material.use() does (see GLShader._bind_textures), just invoked directly rather than driven by material property data.

Deliberately does NOT go through TextureManager.bind_texture()/ _allocate_slot() - that slot counter is reset and reallocated from 0 by every single GLShader.draw_mesh() call (see its begin_draw()), completely independent of this kernel's own _next_unit/ _buffer_units bookkeeping in _bind_texture_buffer() below. Buffer textures (bvh_aabb/bvh_meta/triangles) are bound once at upload_scene() time and never rebound, so if this used TextureManager's counter too, whatever unit the last mesh drawn that frame happened to leave it at could easily collide with one of those - two active samplers of different types (samplerBuffer vs. sampler2D) bound to the same unit, which is a GL_INVALID_OPERATION at draw time. Continuing this kernel's own counter instead keeps every uniform this program has ever bound at a distinct, stable unit for the program's whole lifetime.

blit_to_screen(name, size=None) #

Blits one @output field's result directly to whatever framebuffer is currently bound (0 = 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 Framebuffer.draw(), which the rest of the engine already uses for showing a G-buffer channel.

destroy() #

Releases every TextureBuffer 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 GLComputeShader 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: (re)creates the backing FBO (one float attachment per @output field, sized to width/height) only when the size actually changed, binds it, updates the DISPATCH_SIZE/TIME builtin uniforms if the kernel declared them, disables depth testing (there's no depth buffer here, and a stale depth-test state could otherwise discard the fullscreen triangle), and issues glDrawArrays(GL_TRIANGLES, 0, 3) against the shared attributeless VAO - the vertex shader derives full-screen coverage purely from gl_VertexID, so one triangle covers every pixel and the fragment shader runs exactly once per output pixel, i.e. once per logical invocation.

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 Framebuffer.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 GLShader.set_uniform() uses. Warns instead of raising if name isn't an active uniform.

GLRaytraceShader(source, injector=None) #

Bases: GLComputeShader

A @raytrace kernel: the same fullscreen-pass dispatch mechanism as GLComputeShader, plus scene data (a BVH and its triangles) uploaded as buffer 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.

Compiles source as a RAYTRACE-stage kernel (so GL33Generator emits the trace_ray()/make_ray()/etc. intrinsics), leaving the scene buffer-texture 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.