HLSL backend (codegen + D3D11 renderer)#2897
Open
soufianekhiat wants to merge 17 commits into
Open
Conversation
Cross-platform HLSL codegen as a sibling of GenGlsl/GenMsl/GenSlang.
Reuses GLSL node implementations via a small post-emit pass: three
regex rewrites (single-arg vector splat, texture() to mx_texture_sample,
ClosureData return constructor) plus a token table (mix->lerp,
dFdx/dFdy->ddx/ddy, mod->fmod, fract->frac, inversesqrt->rsqrt).
Adds:
- source/MaterialXGenHlsl/{HlslShaderGenerator,HlslSyntax}.{h,cpp}
- libraries/{stdlib,pbrlib,nprlib,lights}/genhlsl/*.mtlx
- libraries/stdlib/genhlsl/lib/{mx_math,mx_texture}.hlsl
- libraries/targets/genhlsl.mtlx
- source/MaterialXTest/MaterialXGenHlsl/* (codegen tests)
- CHANGELOG.md entry
Mirrors MslResourceBindingContext. When attached to GenContext, splits uniforms into Private/Public/LightData cbuffers with explicit register annotations and suppresses inline LightData struct emission (the binding context emits it once at the cbuffer level).
…ction Renderer-free compile + reflect entry point. FXC via d3dcompiler_47 (default, SM 5.x); DXC via dxcompiler.dll loaded dynamically (SM 6.x). Reflection unifies on HlslResourceBinding for both DXBC and DXIL. Suitable for headless CI to validate that generated HLSL compiles without requiring a D3D11 device.
HlslContext owns ID3D11Device + DeviceContext with hardware-or-WARP fallback and tryCreateContext() for headless test environments. HlslFramebuffer wraps an RTV + DSV + readback path so tests can verify real pixels. End-to-end draw test compiles a trivial VS+PS, draws a fullscreen triangle, and reads back the centre pixel.
Bridges D3D11's stateful cbuffer model to MaterialX's per-uniform update pattern. One ID3D11Buffer per stage per cbuffer with a CPU mirror so partial writes do not clobber unrelated members. Reflection- driven member offset lookup (lookupVariableOffset) so callers can name 'u_worldMatrix' and get back its byte offset inside vertexCB. Includes a generated-shader test that compiles standard_surface_carpaint, allocates the reflection-driven cbuffer pool, and draws into the framebuffer to verify the pixel shader actually executed.
SRV + sampler cache keyed by Image::getResourceId. Subclassing ImageHandler gives Python clients the full bindImage / unbindImage / releaseRenderResources interface. getBoundSrv / getBoundSampler expose the COM pointers so the renderer can bind t# / s# slots without re-walking the cache.
Per-frame validateRender walks the program's reflected bindings and auto-binds: camera/world matrices into vertexCB; lighting scalars into pixelCB; environment radiance/irradiance via LightHandler; file textures from PUBLIC_UNIFORMS via ImageHandler; per-light parameters via reflection's indexed-name lookup. patchVariable lets the renderer be cbuffer-agnostic so it works with and without an attached HlslResourceBindingContext.
One-line CRTP-style specialisation of TextureBaker<HlslRenderer, HlslShaderGenerator>. All baking machinery comes from the templated base class; this subclass only wires the backend types in.
PyMaterialXGenHlsl: HlslShaderGenerator, HlslResourceBindingContext, HlslSyntax. PyMaterialXRenderHlsl: HlslContext, HlslFramebuffer, HlslProgram, HlslMaterial, HlslTextureHandler (as ImageHandler subclass), HlslRenderer. D3D COM pointers are never crossed into Python.
Embind binding for HlslShaderGenerator, gated on EMSCRIPTEN. Generator only - no renderer in WASM since D3D11 is not portable.
Five tests were asserting raw pixel byte values that no longer hold since the framebuffer defaults to sRGB encoding and the texture handler builds a mip chain by default: - ClearAndReadback, Draw Triangle, Material BindCbufferAndDraw, DrawsMeshWhenAvailable: opt the framebuffer into linear pass-through via setEncodeSrgb(false) before bind so the linear RTV is used. - Texture SampleAndDraw: a 2x2 source under trilinear filtering blends mip 0 with the gray average mip 1, so corner reads don't return the original texels. Set ImageSamplingProperties::filterType = CLOSEST so the test sees raw texel values.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
MaterialXGenHlslandMaterialXRenderHlsl, + Python and JS bindings, plus the matching libraries underlibraries/{stdlib,pbrlib,nprlib,lights}/genhlsl/. Existing GLSL / MSL / Slang code is untouched.The codegen reuses the GLSL
.glslimpl files viafile="../genglsl/..."and runs a small post-emit pass for the GLSL→HLSL deltas (mix→lerp,dFdx→ddx, vector-splat C-cast,texture()→mx_texture_sample, etc.). Two HLSL-native helpers (mx_math.hlsl,mx_texture.hlsl) fill in the rest.The renderer is D3D11. FXC for SM 5.x, DXC loaded dynamically for SM 6+.
HlslMaterialowns per-stage cbuffers with a CPU mirror so partial uniform writes don't clobber neighbours — D3D11 cbuffers are stateful, noglProgramUniformanalogue.HlslTextureHandleris anImageHandlersubclass.HlslRendererauto-binds camera, lights, env, file textures and multi-mesh geometry from reflection.Tests: 7 cases / 3369 assertions in
[genhlsl], 19 / 213 in[renderhlsl]. Headless CI safe - every D3D-touching case skipscleanly when
tryCreateContext()returns null. The full FXC compile sweep (~22 min) is tagged[!slow]so quick CI runs can skip it.Validation: 31 materials rendered side-by-side against GLSL on the shaderball (StandardSurface, OpenPBR, glTF PBR, Disney, SimpleHair), plus the 15-material chess_set scene. All visually identical; 30/31 single-material RMSE under 2 on the 0-255 scale. See Compare.
Build:
MaterialXGenHlslcross-platform,MaterialXRenderHlslgated onWIN32. Stagesdxcompiler.dll+dxil.dllfrom the Windows SDK.Why not "just emit HLSL with Slang"?
Slang would give us HLSL source, not a D3D11 renderer - we'd still need most of
MaterialXRenderHlsl. And FXC/DXC reflection round-trips MaterialX uniform names directly with native emit; through Slang they get mangled, breaking the per-uniformsetVariableAPI that GLSL/MSL already provide.Disclosure: This PR was created assicted with Claude Opus 4.7.