Texture and sampler pairing
A Direct3D 11 program reads a texture register t<n> with an explicit sampler register s<m> in every sample, gather4 and
lod instruction; the texture’s contents come from the resource bound at the draw, and the filter and addressing from the sampler
state bound at s<m>. The program fixes two things: which sampler register goes with which texture register, and whether the
read compares against a reference (a comparison sampler). A load (ld, bufferLoad, …) uses no sampler. Sekiro’s programs are
Shader Model 5 DXBC and Elden Ring’s Shader Model 6 DXIL; the two pair their registers alike.
One sampler per texture register
Section titled “One sampler per texture register”In a program, a texture register is read through exactly one sampler register, in all but 26 of the 192,998 (program, texture register) pairs that are sampled.
| Sekiro | Elden Ring | |
|---|---|---|
| distinct programs (by file bytes) | 9,371, of which 9,204 read a texture: 6,700 pixel, 2,381 vertex, 70 compute, 38 domain, 15 geometry | 13,423, of which 12,754 read a texture: 7,856 pixel, 4,694 vertex, 143 compute, 36 domain, 25 geometry |
| programs that sample a texture | 6,876 | 8,136 |
| texture registers read (sampled or loaded) | 106,399 | 123,339 |
| sampled | 89,699 | 103,299 |
| sampled through one sampler register | 89,688 | 103,284 |
| sampled through two | 11 (in 10 programs) | 15 (in 13 programs) |
| only loaded, no sampler | 16,700 | 20,040 |
| sampled and loaded | 1 | 1 |
Observed · the programs extracted from each game’s shader bundles, each compared with Microsoft’s own disassembly of it
The register spaces of all these registers are 0. Observed
Every texture and sampler handle of a Shader Model 6 sampling call is made by a createHandle call in the same function; the 3
calls in Elden Ring whose texture register is computed (a texture array indexed in two compute programs) are loads, and no sampler
register is computed. Observed · Elden Ring
Comparison samplers
Section titled “Comparison samplers”An instruction compares exactly when its sampler register is declared a comparison sampler: sample_c_lz (Sekiro, 5,585 calls)
and sampleCmpLevelZero (Elden Ring, 11,116) on a comparison sampler, every other sample and gather (101,668 and 132,245 calls) on a
default sampler. Observed · every sampling call The comparison sampler is always register s12, and no other register is a
comparison sampler. Observed sample_b, sampleBias, sampleCmp and textureGatherCmp do not occur; gather4 and
textureGather are rare (23 and 27 calls).
The sampler registers
Section titled “The sampler registers”The programs name their samplers, and the name of a register is the same in every program that declares it:
| Register | Name | Sekiro programs | Elden Ring programs |
|---|---|---|---|
s6 |
SS_WrapPoint |
3,777 | 4,551 |
s7 |
SS_ClampPoint |
394 | 554 |
s8 |
SS_WrapLinear |
5,051 | 5,945 |
s9 |
SS_ClampLinear |
3,829 | 4,482 |
s10 |
SS_WrapAniso |
68 | 0 |
s11 |
SS_ClampAniso |
0 | 106 |
s12 |
SS_Shadow (comparison) |
1,414 | 1,463 |
Some programs spell the name differently (g_ClampPointSampler, g_samLinearWrap, s_WrapPoint, …) and none declares another
kind of sampler at these registers. Observed · the Resource Bindings table of every program The registers s0 to s4 are the material
samplers of the surface programs: SS_DiffuseMap s0 (5,582 Sekiro and 6,856 Elden Ring programs), SS_SpecularMap s1,
SS_BumpMap s2, SS_MaskMap s3 and SS_DisplacementMap s4. Other programs reuse them under their own names: the
screen-space ambient occlusion, depth-of-field and bilateral programs declare SS_ClampPoint as s2 and SS_ClampLinear as s3,
and SS_WhiteBorderPoint is s4. For these the name carries the meaning and the register does not. Observed
The texture register a given sampler register pairs with differs from program to program: the two numbers are equal in 8,955 of
Sekiro’s 89,688 single-sampler pairs and 10,003 of Elden Ring’s 103,284. Observed
The filter and addressing behind each name are set by the engine when it binds the state and are not stored in the programs.
In frame recordings the engine’s registers hold one fixed state each, the same in both games: Observed[every screen-space and
compute step of 9 Sekiro and 7 Elden Ring recorded frames]
| Register | State |
|---|---|
s6 |
point filter, wrap |
s7 |
point filter, clamp |
s8 |
linear filter (0x15), wrap |
s9 |
linear filter, clamp |
s12 |
comparison filter 0x94 (linear minification and magnification, point mip), comparison GREATER (the depth is reversed), border addressing with border colour 0, 0, 0, 0, LOD range 0 to 0 |
No step binds two different states at one of these registers, over all its runs in the recorded frames. Observed The material
registers s0 to s4 vary from program to program. Observed
Textures read through two samplers
Section titled “Textures read through two samplers”The 26 exceptions are the same texture read through a point sampler and a linear sampler (22) or through the point sampler and the comparison sampler (4). All are pixel programs. Observed
| Program | Texture (register) | Samplers and calls |
|---|---|---|
GXScreenSpaceCascadedShadow_PCF4_Fade, _PCF9_Fade, _Soft_Fade |
g_PrevScreenTexture (t2) |
SS_ClampPoint 1, SS_ClampLinear 1 |
GXScreenSpaceCascadedShadow_Soft, _Soft_Fade |
g_ShadowTexture (t32) |
SS_Shadow 16 (comparison), SS_ClampPoint 4 |
GXSssBlurX, GXSssBlurY |
g_LightAccTexture (t36) |
SS_ClampPoint 1, SS_ClampLinear 16 |
LensSimu2_BlurCoC |
g_CoCTex (t2) |
SS_ClampPoint 1, SS_ClampLinear 8 (Sekiro) or 1 (Elden Ring) |
ScreenSpaceAO2_ReProj, _SeparatedReProj, _WithNormalReProj; only in Elden Ring CopyExternalAOTextureReProj |
g_PrevAOTex (t3) |
SS_ClampPoint 1, SS_ClampLinear 1 |
only in Elden Ring SampleBilateralDepthBlurTwo1, Two2 |
g_SourceTex (t0), and in Two2 g_SourceTex2 (t3) |
SS_ClampLinear 1, SS_ClampPoint 4 |
Observed · all 26 slots
In Sekiro’s g_PrevScreenTexture and g_PrevAOTex programs the two reads use one coordinate register and take different
components of the result (one component through the linear sampler, three through the point sampler); in Elden Ring’s
ScreenSpaceAO2, CopyExternalAOTextureReProj and _Soft_Fade programs they use identical coordinate values. In GXSssBlurX/Y and LensSimu2_BlurCoC the
point-sampled read is at the interpolated texture coordinate and the linear reads are at computed coordinates. In the two
GXScreenSpaceCascadedShadow_Soft programs the shadow map is read four times as plain depth and sixteen times by comparison.
Observed
only in Sekiro Sekiro binds the anisotropic registers with the others, as one table: every draw and dispatch of five
frames at the Ashina Castle gate that binds samplers (12,914 bindings of each register, vertex, pixel, domain and compute
programs) has s10 and s11 set, though no Sekiro program declares s11. Observed · Sekiro · five captured frames
| Register | Outside the shadow maps | In the shadow-map passes | Confidence |
|---|---|---|---|
s5 |
anisotropic filter (0x55), anisotropy 16, wrap |
linear filter (0x15), wrap |
Observed · Sekiro |
s10 |
anisotropic filter (0x55), anisotropy 16, wrap |
linear filter (0x15), wrap |
Observed · Sekiro |
s11 |
anisotropic filter (0x55), anisotropy 16, clamp |
linear filter (0x15), clamp |
Observed · Sekiro |
The states of s6 to s9 and s12 are the same in these frames as in the table above, with no other state at those
registers. Observed · Sekiro · five captured frames SS_ClampAniso at s11 in Elden Ring’s programs is
therefore the second register of the same pair. Inferred The anisotropy of 16 may follow the game’s graphics settings,
which these frames do not vary. Inferred · Sekiro
Elden Ring binds the same three registers with the others: every draw and dispatch that binds samplers in ten Stormveil
gate frames has s5, s10 and s11 set, in vertex, pixel and compute stages. Observed · Elden Ring · ten captured frames
Outside the shadow and depth passes (render targets of 2048², 4096² and 64² texels) s5 and s10 hold the anisotropic wrap
state and s11 the anisotropic clamp state, with the same filter (0x55), anisotropy 16 and border colour (0.5, 0.5, 0.5, 0)
as Sekiro’s; inside those passes all three hold the linear filter (0x15). Observed · Elden Ring · ten captured frames
No drawn Elden Ring program declares s5 or s10, and one declares s11: M[AMSN_V][Mb4][3Mask][Ov_N2]_Gbuf, one to four
draws a frame, which reads Texture2D_0 (Mask3Map, t0) and Texture2D_7 (NormalMap_0, t10) through
SS_ClampAniso. Observed · Elden Ring · ten captured frames
The state of the three registers is read from the frames, and the one drawn reader of s11 is named. No drawn program
reads s5 or s10, so their readers, if any, are not in these frames, and no frame varies the graphics settings that may
set the anisotropy of 16.