Skip to content

Shader bundles and permutations

Shader bundles group compiled programs and binding metadata for one shader family. A material’s shader path names the family; its switches select programs within that family. Observed

The main /shader/shaderbdle.shaderbdlebnd.dcx holds <family>.shaderbdle members. Each is itself a binder of programs and a .metaparam. Observed Elden Ring also has DLC bundle binders named shaderbdle_dlc01.shaderbdlebnd.dcx, shaderbdle_dlc02.shaderbdlebnd.dcx, a separate speedtree.shaderbdlebnd.dcx, and a ray-traced binder beside each of the four: shaderbdle_[rt], Shaderbdle_DLC01_[RT], Shaderbdle_DLC02_[RT] and speedtree_[rt], all under /shader/. Observed · Elden Ring The renderer’s own programs are in binders that hold programs directly, with no bundle level (/shader/<name>.shaderbnd.dcx, listed below). Observed

Property Sekiro Elden Ring Confidence
Compiled programs Shader Model 5 DXBC Shader Model 6 DXIL in DirectX containers Observed
Material parameters Named reflected fields Commonly SAT_MtdParam, with metaparam word offsets Observed
Geometry inputs Ordinary and skinned variants Ordinary, skinned and SpeedTree variants Observed

Elden Ring’s programs all target shader model 6.0, its libraries 6.3: of the 50,283 programs extracted from the 17 shader binders (grass, the gx* program binders, shaderbdle, its DLC and ray-traced binders, speedtree and speedtree_[rt]), 25,183 are ps_6_0, 18,769 vs_6_0, 1,731 cs_6_0, 136 hs_6_0, 150 ds_6_0, 33 gs_6_0 and 4,281 lib_6_3, by each container’s program header, and Microsoft’s DXC 1.9.2609 reads every one of them. Observed · Elden Ring

The parts of these containers, their digest and (for Elden Ring) the PSV0 record and the feature mask are described on Direct3D shader containers.

Stage file extensions agree with the shader kind in their program containers in Sekiro’s bundle census and in the Elden Ring Academy material-bundle comparison. The Sekiro census checks all 16,428 programs in its 248 bundles without a stage mismatch; Elden Ring’s cited check is limited to one area. Proven · Sekiro · all 248 bundles Observed · Elden Ring

Extension Stage Confidence
.vpo Vertex Proven · Sekiro · all 248 bundles Observed · Elden Ring
.ppo Pixel Proven · Sekiro · all 248 bundles Observed · Elden Ring
.hpo Hull Proven · Sekiro · all 248 bundles Observed · Elden Ring
.dpo Domain Proven · Sekiro · all 248 bundles Observed · Elden Ring
.gpo Geometry Observed · Elden Ring
.cpo Compute, and DirectX Raytracing libraries Observed · Elden Ring

Elden Ring’s three material binders (shaderbdle, _dlc01, _dlc02) hold only the first four kinds. Its 33 .gpo programs are all in the program binders, and of its 6,012 .cpo the program binders hold 179 and the bundles of the [rt] and speedtree binders the rest. Over all 50,283 programs read from its shader binders, the count of each extension equals the count of containers of the matching kind: 33 .gpo and 33 geometry programs, and 6,012 .cpo against 1,731 compute programs plus 4,281 library containers. Observed[the counts of every program read]{games=“elden-ring”}

Over 9,371 Sekiro DXBC programs and 13,423 Elden Ring DXIL programs, a texture register is sampled through exactly one sampler register in all but 26 of the 192,998 program and texture-register pairs: 22 of those use both SS_ClampPoint and SS_ClampLinear, 4 both SS_ClampPoint and SS_Shadow. Every comparison sample uses the comparison sampler at s12, and every resource is in register space 0. The pairs read from the programs equal the disassembly of Microsoft’s compilers (fxc, dxc) on every program. Observed · the programs read

Registers Samplers Confidence
s0–s4 the material’s samplers; ambient-occlusion, depth-of-field and bilateral-filter programs reuse these registers for their own Observed
s6 SS_WrapPoint Observed
s7 SS_ClampPoint Observed
s8 SS_WrapLinear Observed
s9 SS_ClampLinear Observed
s6–s12 also an anisotropic sampler: SS_WrapAniso only in Sekiro, SS_ClampAniso only in Elden Ring Observed
s12 SS_Shadow, the comparison sampler Observed

The sampler states recorded in frame captures of both games match these names. s12 has filter 0x94 (comparison, linear minification and magnification, point mip), comparison GREATER, border colour 0 and LOD range 0 to 0. Observed · frame captures

Every shader family of both games ships its _Gbuf, _Fwd, _FwdSdw and _FwdSSdw pixel programs and a _Fwd.vpo. Observed Which of them a material is drawn with follows its definition: a material is drawn forward (a _Fwd… pixel program, target 0 its finished colour) when its MTD or MATBIN states g_GX_ForwardRendering true or g_BlendMode 2, and through the G-buffer otherwise. Every family the recorded frames draw only forward has all its definitions forward by that rule, and no family they draw only through the G-buffer has a definition stating g_GX_ForwardRendering. Observed[9 Sekiro frames of 4 sessions and 7 Elden Ring frames, programs matched by their bytes] Sekiro’s sky dome and far mountains state g_BlendMode 0 with g_GX_ForwardRendering, and Elden Ring’s M[Sky9], M[Clouds9], M[Clouds5] and M[DistantClouds]_001 state the flag. Observed The one exception is Elden Ring’s character-creator hair planes P[ChrCustomize] (blend mode 0), drawn forward in several passes. Observed · Elden Ring No recorded frame draws a material of blend mode 3, 4 or 5 without the flag. Observed

Every forward colour draw of the recorded Elden Ring frames matches an _FwdSdw program by its bytes (86 of 86). Observed · Elden Ring A family’s forward variants can be the same bytes, though (below), so a program matched by its bytes does not always tell its pass.

A forward program finishes its colour itself, so it reads frame inputs that a G-buffer program leaves to later passes. In disassembly (cb8 is the scene buffer, cb5 cbLight, cb9 cbPerFrame):

Input Use Confidence
Shadow map g_ShadowTexture (t32, 2-D) Sekiro’s shadowed forward programs compare against it with sample_c_lz through the comparison sampler SS_Shadow (s12): four reads in MetallicValue_MeshDecal_FwdSdw, and the seven FwdSdw materials of m11_01 bind the same pair Observed · Sekiro · one program read; seven bound
Volumetric fog g_VolumeFog0 (t47, 3-D) colour * exp2(log2(fog.w) * k) + fog.xyz, then times SC_PreExposure (cb8[72].z): w is the transmittance and xyz the in-scattered light, so no fog is (0, 0, 0, 1) and a fog of zeros turns the colour black; in Sekiro’s MetallicValue_MeshDecal_FwdSdw and Elden Ring’s M[Sky9], M[Clouds5] and M[DistantClouds] FwdSdw programs Observed · those programs
FC_VolumeFogParam[4] (cb8[67] to cb8[70]) read by the sky dome and far-mountain programs of m11_01, whose height-fog branch divides by FC_VolumeFogParam[1].xyz, so zeros there give NaN; the same programs read FC_ScreenSize at cb8[1] and FC_DirLightVec_0 at cb5[0] Observed · Sekiro · two programs
FC_TimeOfDay (cb9, register 27 y) Elden Ring’s sky programs (M[DistantClouds]_001_FwdSdw, M[Atmosphere][Clouds]_001_FwdSdw and others) read it in hours: frem(t, 24), then saturated ramps blend the material’s colour keys by the hour, so an hour of 0 gives the night keys Observed · Elden Ring
M[Sky9]_FwdSdw and M[Clouds5]_FwdSdw read it the same way, and every palette parameter they blend (60 names for M[Sky9], 129 for M[Clouds5]) is in their MATBIN definitions; in one recorded Stormveil frame the two draws’ material constants equal the values built from those definitions in all 198 and 266 float lanes. The hour word itself was not captured in that frame Observed · Elden Ring · two recorded draws
Sekiro’s programs declare it and never read it: the resource definitions mark it unused in M[Sky]_SkyDome_Ver2_0_Fwd, CloudFog, FarMountain and AMSN Observed · Sekiro
Scene registers cb8[77] to cb8[88] read by Elden Ring’s sky programs besides the above; by their neighbours, fog, atmosphere and sun values Observed · Elden Ring Inferred · Elden Ring · their meaning

Sekiro’s M[LandScape]_FarMountain dithers its fade: it keeps a fragment where (noise - 0.5) * 0.999 + ditherFadeAlpha >= 0.5, so a fade of 0 discards every fragment and a fully shown mountain has a fade of 1. Observed · Sekiro · the program

Elden Ring’s M[DistantClouds]_001_Fwd.vpo (the Field_Skysphere_Clouds_410, _411, _420 and _421 materials of AEG096_410 and _420) writes a cull distance (the length of the vertex’s offset from a point, minus a constant) and two clip distances, and its POSITION1 output is the clip position again, which M[DistantClouds]_001_FwdSdw.ppo divides by its w. Run with the material’s own constants and textures, the pixel program gives (0, 4, 0, 0) for any POSITION1 with w 0 (a NaN through its HSV step) and a dark grey of about 0.05 for a real position. Observed · Elden Ring · the programs lifted and run, tile m60_42_36_00 Eight other sky vertex programs (M[Clouds5], M[Atmosphere][Clouds] and others) declare TEXCOORD0 as a float4 holding UV set 0 in xy and set 1 in zw; the sky models AEG096_* carry up to five UV sets stored as floats (AEG096_010’s first set ranges from −15.9 to 15.3). Observed · Elden Ring

The binding metadata is described in METAPARAM; material upload rules in constant binding.

Sekiro layered materials select <family>_<switch>_Gbuf.ppo using GXFT_SATStaticSwitch. The unskinned vertex program is <family>_Gbuf.vpo, and the skinned variant is <family>_Gbuf_Skin.vpo. Observed · Sekiro

Alpha-tested pixel permutations carry _[A] and discard against FC_AlphaRef. The same family can contain forward programs with _Fwd, and shadowed forward variants _FwdSdw and _FwdSSdw. Observed · Sekiro

The renderer numbers its passes, and a program’s pass suffix is the name of its pass id: 0 Fwd, 1 Velo, 2 Dpt, 3 DptA, 4 FwdSdw, 5 FwdSSdw, 6 FwdSsr, 7 FwdDpt, 8 Gbuf, 9 GBufDpt, 10 Pnt, 11 Pnt[M], 12 PntCol, 13 PntWetH, 14 SO, 15 WatDpt, 16 Spec, 17 Aof, 18 Rsm, 19 Voxelization, 20 FwdDbg, 21 FwdSdwDbg, 22 GBufDbg. Beside that table the executable keeps the geometry suffixes _Skin, _MorphSkin, _Morph, @[cl], _FT, _FT_D, _PN and _PN_D, and the alpha-tested form %s_[A]. Inferred · Sekiro · read from the decrypted executable of Sekiro 1.06 The loaders of the material shader banks and of GXFlver load every pass’s program, <shader>_<pass>, into a set per shader indexed by pass, with each pass’s _[A] program beside it. A draw then takes its program from the set by the pass id of the pass drawing it (for a GXFlver material, entry (pass + 1) * 3 + alpha), so the material does not pick its forward variant. Which passes draw a material is a mask test: a category word the material computes from its definition when it is set up (g_GX_ForwardRendering gives category 2), with the model’s flags, against each pass’s own mask. Inferred · Sekiro · read from the decrypted executable of Sekiro 1.06

At the Ashina Castle gate at night, the sky dome, the far mountains and the cloud and ground fog draw in pass 0 (Fwd), and the characters and GXFlver_ColDif draws in pass 4 (FwdSdw). Observed[a read-only breakpoint on the draw’s pass id in the running game]{games=“sekiro”} M[Sky]_SkyDome_Ver2, M[Moon] and M[LandScape]_FarMountain have byte-identical _Fwd, _FwdSdw and _FwdSSdw pixel programs. Proven · Sekiro · every forward program of the main bundle compared by its bytes

The forward pass is chosen per draw job, when the job is set up. For a job of draw phase 0 or 15 the pass becomes 4 (FwdSdw), or 5 (FwdSSdw) when the renderer’s shadow setting is 3, if shadows are on and bit 0 of a flag byte of the job’s descriptor is clear; otherwise it stays 0 (Fwd). That bit is copied from a byte of the job’s input, and the program is then entry (pass + 1) * 3 + alpha of the set. Inferred · Sekiro · read from the decrypted executable of Sekiro 1.06 In the breakpoint record above, the pass-0 draws are the cloud fog and ground fog, whose layout parts have the shadow-receive flag (byte +0x11 of the part’s entity data) clear, and the sky dome and far mountains, which no layout places; the pass-4 draws are of parts with the flag set. Both passes run with the same draw-list filter and the same material mask. Observed · Sekiro Over the layouts of the nine maps, of the 527 forward models a layout places, 22 are placed with the flag clear (21 fog and smoke models and one mesh decal) and 505 with it set, and no model is placed both ways. Observed · Sekiro · the layouts of nine maps So a forward material draws with FwdSdw where its placements receive shadows and with Fwd where they do not. Inferred · Sekiro

The forward pass’s target 0 is finished colour, unlike the deferred pass’s G-buffer targets. Forward programs can read scene depth, SSAO, irradiance volumes, IBL cubemaps and fog in addition to material textures. Observed · Sekiro

The Wolf’s default outfit (fc_m_0200, bd_m_9040, am_m_9000, lg_m_9000) has four material variants that output colour from a forward program and have no albedo output, and the Ashina costume two. They use three pixel programs, MeshDecal_Fwd, AMSN_Fwd and AMSN_Fwd_[A], and every RGB output of each depends on the lighting, IBL, irradiance, SSAO, fog and camera or frame constants as well as the material, so a forward variant’s colour is not its albedo. Observed · Sekiro · a dependency trace of those programs’ outputs

The Character_AMSN_[AO_SSS] pixel programs sample 17 textures in one stage. Observed · Sekiro

Sekiro’s GXFlver_* material programs instead live together in /shader/gxflvershader.shaderbnd.dcx. Their instance-dependent effect variants include Bloody, Burn, Cm, Df, Cloth, Phantom, ZFeather and Decal; a material definition alone does not identify which effect an instance uses. Observed · Sekiro

The programs that draw effects (billboards, tracers, distortion, the particles on the GPU) are in a bundle of their own, /shader/gxffxshader.shaderbnd.dcx, described on effect shader programs. Observed · Sekiro

In a castle-interior capture, Sekiro uses reversed depth with GreaterEqual, and disables depth writes on matched materials carrying g_GX_bDisableDepthWrite. Matched g_BlendMode = 2 forward draws use additive SrcAlpha / InvSrcAlpha colour blending and One / Zero alpha blending; G-buffer draws do not blend. The captured cull state follows the face set rather than a single material-wide value. Observed · Sekiro

Five frames at the Ashina Castle gate, the model draws tied to their materials, bind these states by pass and blend mode; depth is reversed throughout (GreaterEqual): Observed · Sekiro · five captured frames

Pass g_BlendMode Colour Depth Draws
G-buffer 0 no blending written 2,736
G-buffer 0 not written written 151
G-buffer 0 no blending tested Equal, not written 151
G-buffer 2 SrcAlpha / InvSrcAlpha, RGB only written 45
lit image (two R11G11B10_FLOAT targets) 0 SrcAlpha / InvSrcAlpha written 10
lit image 2 SrcAlpha / InvSrcAlpha written 75
lit image 2 not written written 20
motion vectors (R16G16_FLOAT) 0 no blending written 320
motion vectors 2 no blending written 20
shadow maps 0 no colour target written 1,819
shadow maps 2 no colour target written 10

The two sets of 151 are the same M[MultipleGround] ground: drawn first to depth alone, then again for its colour with an Equal depth test. Observed · Sekiro · five captured frames The decal meshes (MetallicValue_MeshDecal) are the G-buffer’s blend-mode-2 draws: they blend into all five targets with the alpha lane masked off, so they leave each target’s alpha as the surface under them wrote it. Observed · Sekiro · five captured frames Every shadow-map draw has a slope-scaled depth bias of −3 and every motion-vector draw one of 10 clamped at −0.005. In the G-buffer, 95 draws (decals, metallic, layered and translucent families) have a slope-scaled bias of 3 and 2,988 none; draws of one material occur both with and without it. Observed · Sekiro · five captured frames

Each of these /shader/<name>.shaderbnd.dcx binders holds programs directly. Every one was read from the archives, with these members: Observed · Elden Ring · every member of the nine binders

Binder .ppo .vpo .hpo .dpo .gpo .cpo
grass 8 2
gxdecal 42 10
gxffxshader 279 41 25 39 27 77
gxflvershader 94 148 6
gxgui 14 3
gxposteffect 173 8 12
gxrenderershader 165 21 1 1 6 70
gxshader 20 6
GXRayTracing 14

The bundle binders beside them hold .shaderbdle members: 750 in shaderbdle_[rt], 87 in Shaderbdle_DLC01_[RT], 120 in Shaderbdle_DLC02_[RT], and 111 each in speedtree and speedtree_[rt]. Observed · Elden Ring

GXRayTracing holds ray-tracing shaders: 9 of its 14 programs are DirectX Raytracing libraries with one entry function each (3 ray generation, 2 miss, 2 closest-hit and 2 any-hit), and 5 are compute programs. Observed · Elden Ring · all 14 members That leaves 4,272 of the game’s libraries, 2,136 any-hit and 2,136 closest-hit, to the other binders; that they are the hit shaders of the [rt] material bundles is a reading of the binders’ names, not a check. Inferred · Elden Ring

Three independent readers, one of them Microsoft’s DXC reflection, give the same resource bindings for every program of the 17 shader binders above (the three material binders, the five other bundle binders and the nine program binders): 50,281 distinct programs, with each binding’s name, class, register space, register and count equal and no program refused by any reader. Every binding is in register space 0, and no binding is an array of unstated size. Proven[every program of the 17 binders read]{games=“elden-ring”}

Material binders The other 14 binders Confidence
Distinct programs 40,585 (22,945 pixel, 17,420 vertex, 110 hull, 110 domain) 9,696 (2,236 .ppo, 1,349 .vpo, 6,012 .cpo, 40 .dpo, 26 .hpo, 33 .gpo) Proven · Elden Ring
Bindings 693,967 84,526 Proven · Elden Ring
Constant buffers 249,634 31,280 Proven · Elden Ring
Shader resource views 353,056 39,634 Proven · Elden Ring
Samplers 91,277 11,627 Proven · Elden Ring
Unordered-access views none 1,985 Proven · Elden Ring
Arrays (a count above 1) none 37 Proven · Elden Ring

No two of the 40,585 material programs have the same bytes, every one has at least one binding, and 12,625 have 20 or more. Proven · Elden Ring · every program of the three material binders So a material program binds each resource on its own register in space 0, and unordered-access views and arrays occur only in the other 14 binders. Proven · Elden Ring · every program of the 17 binders read The .devpatch binders that the archive dictionary also names under /shader/ (shaderbdle.shaderbdlebnd.devpatch.dcx and others) were not read. Sourced · Elden Ring · UXM Selective Unpack

An _[A] program does not always test a surface alpha. The G-buffer programs M[AMSN_V][Mb4][3Mask][Ov_N2][beach]_Gbuf_[A] and M[AMSN_V][Mb2]_Gbuf_[A] discard, besides two fade tests, when 1.0 + FC_AlphaRef.y * (g_DitherTexture.w - 0.5) < FC_AlphaRef.x: the tested value is the constant 1.0 moved only by the dither, with no texture alpha in it. At the neutral dither of 0.5 it is 1.0 over the whole surface, so with a reference of 1.0 (g_AlphaRef 255) or below the program keeps every pixel, and such a material draws as opaque whatever its albedo alpha holds. Observed[DXIL disassembly of the two programs, and running them at their materials’ references over the Limgrave tile m60_42_36_00]{games=“elden-ring”} Other alpha-tested materials of the same tile (aet801_270_a, aet030_075_a and four more) compare a sampled texture alpha with the reference, and their programs’ discards match alpha < reference at every texel. Observed · Elden Ring · same tile

What selects every runtime permutation and render state?

The material switch does not explain every instance-dependent pass choice. No captured Sekiro frame draws blend modes 3–5, and the G-buffer’s depth bias differs between draws of one material, so no material field predicts it. Unknown · Sekiro