HLSL Code Generation
SkillAI & modelsHLSL code generation, StringBuilder patterns, builtin headers, and DXIL embedding.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the HLSL Code Generation skill
What this skill tells your AI
The instructions your AI receives, as published by luisagroup/luisacompute in .agents/skills/hlsl/SKILL.md and read by ahel’s review.
Codegen utilities using vstd::StringBuilder and formatting helpers.
StringBuilder
#include <luisa/vstl/string_builder.h>
vstd::StringBuilder builder;
builder.clear();
size_t sz = builder.size();
vstd::string_view view = builder.view();
char* data = builder.data();
Appending
str.append("Hello");
str += "World"sv;
str.append(' ');
str << '\n';
str.append(other_builder);
str << "func" << '(' << ")";
Numbers
vstd::to_string(42, str); // int (faster than format)
vstd::to_string(3.14f, str); // float
str << luisa::format("{}", 42);
str << luisa::format("{}, {}!", "Hello", "World");
str << luisa::format("{:016X}", hash);
String View Literals
using namespace std::string_view_literals;
str += "void"sv; // no allocation
Code Generation Patterns
Function Declaration
void GetFunctionDecl(Function func, vstd::StringBuilder &str) {
vstd::StringBuilder data;
if (func.return_type()) CodegenUtility::GetTypeName(*func.return_type(), data, Usage::READ);
else data += "void"sv;
data += " "sv;
CodegenUtility::GetFunctionName(func, data);
data += '(';
for (auto &&arg : func.arguments()) {
Usage usage = func.variable_usage(arg.uid());
CodegenUtility::GetTypeName(*arg.type(), data, usage);
data << ' ';
vstd::StringBuilder varName;
CodegenUtility::GetVariableName(func, arg, varName);
data << varName << ',';
}
if (!func.arguments().empty()) data[data.size() - 1] = ')';
else data += ')';
str << '\n' << data;
}
Template Parameters
str << "template<"sv;
for (uint64 i = 0; i < tempIdx; ++i) {
str << "typename T"sv; vstd::to_string(static_cast<int64_t>(i), str); str << ',';
}
if (tempIdx > 0) *(str.end() - 1) = '>';
Call Expression
str << "func_name"sv << '(';
if (!args.empty()) {
for (size_t i = 0; i < args.size() - 1; ++i) { args[i]->accept(vis); str << ','; }
args.back()->accept(vis);
}
str << ')';
Type-Aware Generation
if (t->is_texture() || t->is_buffer()) { str << 'T'; vstd::to_string(tempIdx++, str); }
else if (t->is_vector()) { str << "float"sv; vstd::to_string(t->dimension(), str); }
else if (t->is_matrix()) { auto n = vstd::to_string(t->dimension()); str << "_float"sv << n << 'x' << n; }
RAII Wrapping
struct CodeWrapper {
vstd::StringBuilder *_result;
CodeWrapper(vstd::StringBuilder *r, string_view open) : _result(r) { if (_result) *_result << open; }
~CodeWrapper() { if (_result) *_result << ')'; }
};
CodeWrapper wrapper{&str, "to_float4x4("};
// inner content generated; ')' appended automatically
Trailing Comma Fix
str << '(';
for (auto &&item : items) str << item << ',';
if (!items.empty()) str[str.size() - 1] = ')';
else str << ')';
Iteration & Hash
for (char c : str) {}
str.erase(str.begin() + 5);
vstd::hash<vstd::StringBuilder> hasher; size_t h = hasher(builder);
if (builder1 == builder2) {}
if (builder1 == "literal"sv) {}
Best Practices
- Use
"text"svliterals to avoid allocations vstd::to_string()for integers (faster thanluisa::format())builder.reserve(1024)when size knownoperator<<for chaining,operator+=for single items- Check
size()before modifying last character
HLSL Builtins
Located in src/backends/common/hlsl/builtin/. Access via:
#include <backends/common/hlsl/builtin/hlsl_builtin.hpp>
auto header = lc_hlsl::get_hlsl_builtin("hlsl_header");
std::string_view code(static_cast<const char*>(header.ptr), header.size);
Header Files (.bytes)
| Key | Description |
|---|---|
hlsl_header | Main HLSL header |
hlsl_header_fallback | Fallback header |
spv_alias | SPIR-V aliases |
bindless_upload.bytes / bindless_upload_vk.bytes | Bindless upload helpers |
accel_process.bytes / accel_process_vk.bytes | Acceleration-structure processing |
accel_process_vk_motion.bytes | Acceleration-structure processing with motion blur |
raytracing_motion_header | Ray tracing motion blur |
dx_linalg | Linear algebra utils (DXIL) |
vk_linalg | Linear algebra utils (SPIR-V) |
raytracing_header | Ray tracing |
tex2d_bindless / tex3d_bindless | Bindless textures |
compute_quad | Compute quad ops |
determinant / inverse | Matrix ops |
indirect | Indirect dispatch/draw |
resource_size | Resource queries |
accel_header | Acceleration structures |
copy_sign | Sign ops |
bindless_common | Bindless utils |
auto_diff | Autodiff |
reduce | Parallel reduction |
DXIL Files (.dxil)
| Key | Description |
|---|---|
accel_process_vk.dxil | Vulkan acceleration structures |
load_bdls.dxil / load_bdls_vk.dxil | Bindless loading |
set_accel4.dxil | Set acceleration structure |
bc6_encodeblock.dxil / bc6_trymodeg10.dxil / bc6_trymodele10.dxil | BC6 compression |
bc7_encodeblock.dxil / bc7_trymode02.dxil / bc7_trymode137.dxil / bc7_trymode456.dxil | BC7 compression |
Adding Builtins
- Add
.bytesor.dxiltosrc/backends/common/hlsl/builtin/ - Declare:
LC_HLSL_DECL_VARNAME(my_bytes) - Register:
LC_HLSL_INSERT_VARNAME(my_bytes, "my_key")
Build: .hlsl → .bytes, shaders → .dxil, embedded via bin2obj.
Codegen Debug
Set env LUISA_DUMP_SOURCE=1 to dump generated HLSL to per-shader files.
Output: hlsl_output_<shader_name>.hlsl in the working directory.
Naming priority depends on the backend and shader path:
DX compute / raster / save paths:
ShaderOption::name/fileName— user-provided nameFunction::name()— kernel/callable debug nameFunction::hash()formatted as hex — fallback (e.g.hlsl_output_a1b2c3d4.hlsl)
VK internal builtin compute helpers only (ComputeShader::compile_builtin_hlsl_to_spirv):
file_name— user-provided / cached name- Generated HLSL MD5 — fallback
VK raster (VkRasterExt):
ShaderOption::name is always required, so the dump file uses that name.
VK user compute shaders must use native SPIR-V codegen (LUISA_XIR_TO_SPIRV or LUISA_AST_LLVM_TO_SPIRV); the Vulkan Function compute path must not call HLSL/DXC.
Files are written with "wb" (overwrite) — no need to delete old files.
Each shader gets its own file; no more single hlsl_output.hlsl with appended content.
Signals
- GitHub stars
- 1k
- Forks
- 108
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
hlsl- Source
- github.com/luisagroup/luisacompute