Overview
simple_shaderc provides runtime shader compilation capabilities using Google's shaderc library from the Vulkan SDK. It enables Eiffel applications to compile GLSL shader source code to SPIR-V binary format at runtime.
This enables powerful workflows such as:
- Dynamic Shader Generation - Generate shaders from Eiffel DSL at runtime
- Hot Reloading - Modify and recompile shaders without restarting
- Procedural Content - Create shaders programmatically based on scene data
Part of the Simple Eiffel ecosystem.
Quick Start
Prerequisites
- Install Vulkan SDK
- Set the environment variable:
set SIMPLE_EIFFEL=D:\prod
Installation
- Add to your ECF file:
<library name="simple_shaderc" location="$SIMPLE_EIFFEL/simple_shaderc/simple_shaderc.ecf"/> - Copy the shaderc DLL to your application directory:
copy %VULKAN_SDK%\Bin\shaderc_shared.dll your_app_directory\
Basic Usage
local
shaderc: SIMPLE_SHADERC
spirv: detachable MANAGED_POINTER
glsl: STRING
do
glsl := "[
#version 450
layout(local_size_x = 64) in;
layout(std430, binding = 0) buffer Data { float values[]; };
void main() {
uint idx = gl_GlobalInvocationID.x;
values[idx] = values[idx] * 2.0;
}
]"
create shaderc.make
spirv := shaderc.compile_compute (glsl)
if attached spirv as spv then
print ("Compiled to " + spv.count.out + " bytes")
else
print ("Error: " + shaderc.last_error)
end
shaderc.dispose
end
Key Features
Runtime Compilation
Compile GLSL shaders to SPIR-V at runtime without offline tools.
Multiple Shader Types
Support for compute, vertex, and fragment shaders.
Error Reporting
Detailed compilation error messages for debugging.
SPIR-V Output
Direct binary output ready for Vulkan consumption.
File I/O
Save compiled shaders to disk for caching or distribution.
Vulkan SDK Integration
Uses battle-tested shaderc library from Vulkan SDK.
API Reference
SIMPLE_SHADERC (Facade)
Main entry point for shader compilation.
Initialize the shader compiler. Must be called before any compilation.
Compile GLSL source to SPIR-V bytes. Returns Void on failure.
Preconditions
Convenience method to compile a compute shader.
Convenience method to compile a vertex shader.
Convenience method to compile a fragment shader.
Save compiled SPIR-V binary to file.
Release compiler resources. Must be called when done.
Status Queries
| Feature | Description |
|---|---|
last_error |
Error message from last failed compilation |
has_error |
True if last compilation failed |
is_valid |
True if compiler is properly initialized |
Shader Type Constants
| Constant | Value | Description |
|---|---|---|
Shader_vertex |
0 | Vertex shader for vertex transformation |
Shader_fragment |
1 | Fragment shader for pixel shading |
Shader_compute |
2 | Compute shader for GPU parallel computation |
Recipes
Recipe 1: Compile and Save Shader
compile_and_save (a_glsl, a_output_path: STRING)
-- Compile GLSL and save to file.
local
shaderc: SIMPLE_SHADERC
spirv: detachable MANAGED_POINTER
do
create shaderc.make
spirv := shaderc.compile_compute (a_glsl)
if attached spirv as spv then
shaderc.save_spirv (spv, a_output_path)
print ("Saved: " + a_output_path + "%N")
else
print ("Error: " + shaderc.last_error + "%N")
end
shaderc.dispose
end
Recipe 2: Dynamic SDF Shader Generation
generate_sdf_shader: STRING
-- Generate and compile SDF ray marching shader.
local
builder: SDF_GLSL_BUILDER
shaderc: SIMPLE_SHADERC
spirv: detachable MANAGED_POINTER
scene: STRING
do
-- Define scene in GLSL
scene := "[
float d = 1e10;
d = opUnion(d, sdSphere(p, vec3(0, 1, 0), 1.0));
d = opSmoothUnion(d, sdBox(p, vec3(2, 0.5, 0), vec3(0.5)), 0.3);
return d;
]"
-- Generate full shader
create builder.make
Result := builder.generate_basic_shader (scene)
-- Compile and verify
create shaderc.make
spirv := shaderc.compile_compute (Result)
if spirv = Void then
print ("Shader error: " + shaderc.last_error)
end
shaderc.dispose
end
Recipe 3: Batch Shader Compilation
compile_all_shaders (a_shaders: HASH_TABLE [STRING, STRING]; a_output_dir: STRING)
-- Compile multiple shaders (name -> source).
local
shaderc: SIMPLE_SHADERC
spirv: detachable MANAGED_POINTER
do
create shaderc.make
across a_shaders as s loop
spirv := shaderc.compile_compute (s.item)
if attached spirv as spv then
shaderc.save_spirv (spv, a_output_dir + "/" + s.key + ".spv")
print ("OK: " + s.key + "%N")
else
print ("FAIL: " + s.key + " - " + shaderc.last_error + "%N")
end
end
shaderc.dispose
end
Recipe 4: Integration with simple_vulkan
run_dynamic_compute (a_glsl: STRING)
-- Compile and execute a compute shader dynamically.
local
shaderc: SIMPLE_SHADERC
vk: SIMPLE_VULKAN
ctx: VULKAN_CONTEXT
shader: VULKAN_SHADER
spirv: detachable MANAGED_POINTER
do
-- Compile GLSL to SPIR-V
create shaderc.make
spirv := shaderc.compile_compute (a_glsl)
if attached spirv as spv then
-- Save to temp file
shaderc.save_spirv (spv, "temp_compute.spv")
-- Load with Vulkan
create vk
ctx := vk.create_context
if ctx.is_valid then
shader := vk.load_shader (ctx, "temp_compute.spv")
if shader.is_valid then
-- Create pipeline and dispatch...
print ("Shader loaded successfully!%N")
shader.dispose
end
ctx.dispose
end
else
print ("Compilation failed: " + shaderc.last_error + "%N")
end
shaderc.dispose
end
Error Handling
The shaderc compiler provides detailed error messages for GLSL syntax and semantic errors:
local
shaderc: SIMPLE_SHADERC
spirv: detachable MANAGED_POINTER
bad_glsl: STRING
do
bad_glsl := "#version 450%Nvoid main() { undefined_function(); }"
create shaderc.make
spirv := shaderc.compile_compute (bad_glsl)
if spirv = Void then
print ("Compilation failed:%N")
print (shaderc.last_error)
-- Output: shader.glsl:2: error: 'undefined_function' : no matching overloaded function found
end
shaderc.dispose
end
Common Errors
| Error | Cause | Solution |
|---|---|---|
| "no matching overloaded function" | Undefined function or wrong arguments | Check function name and parameter types |
| "local_size_x: no such layout identifier" | Wrong shader type for compute shader | Use compile_compute for compute shaders |
| "undeclared identifier" | Variable used before declaration | Declare variables before use |
Performance
Compilation performance on typical hardware:
| Operation | Time |
|---|---|
| Compiler initialization | <5ms |
| Simple shader (50 lines) | <50ms |
| Complex SDF shader (300+ lines) | ~100ms |
| Save SPIR-V to disk | <1ms |
Tip: For production, consider caching compiled SPIR-V files rather than recompiling on every startup.