@@ -70,7 +70,7 @@ UTEST( ShaderInternal, StateToDesc )
7070 nvrhi::RasterState rs = vhTranslateRasterState ( VRHI_STATE_DEFAULT );
7171 EXPECT_EQ ( rs.cullMode , nvrhi::RasterCullMode::Back );
7272
73- nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEFAULT , 0 , 0 );
73+ nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEFAULT , VRHI_STENCIL_NONE );
7474 EXPECT_TRUE ( ds.depthTestEnable );
7575 EXPECT_EQ ( ds.depthFunc , nvrhi::ComparisonFunc::Less );
7676 EXPECT_TRUE ( ds.depthWriteEnable );
@@ -85,7 +85,7 @@ UTEST( ShaderInternal, StateToDesc )
8585
8686 // Test Depth Always
8787 {
88- nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEPTH_TEST_ALWAYS , 0 , 0 );
88+ nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEPTH_TEST_ALWAYS , VRHI_STENCIL_NONE );
8989 EXPECT_TRUE ( ds.depthTestEnable );
9090 EXPECT_EQ ( ds.depthFunc , nvrhi::ComparisonFunc::Always );
9191 }
@@ -100,7 +100,7 @@ UTEST( ShaderInternal, StateToDesc )
100100 VRHI_STENCIL_OP_FAIL_Z_REPLACE |
101101 VRHI_STENCIL_OP_PASS_Z_INCR ;
102102
103- nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEFAULT , stencil, VRHI_STENCIL_NONE );
103+ nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEFAULT , stencil );
104104
105105 EXPECT_TRUE ( ds.stencilEnable );
106106 EXPECT_EQ ( ds.stencilRefValue , 0x80 );
@@ -117,22 +117,143 @@ UTEST( ShaderInternal, StateToDesc )
117117 EXPECT_EQ ( ds.backFaceStencil .passOp , nvrhi::StencilOp::IncrementAndWrap );
118118 }
119119
120- // Test Stencil Separate
120+ // Test Stencil Separate (manually packed into single uint64_t)
121121 {
122122 uint64_t front = VRHI_STENCIL_TEST_ALWAYS | VRHI_STENCIL_OP_PASS_Z_KEEP ;
123123 uint64_t back = VRHI_STENCIL_TEST_NEVER | VRHI_STENCIL_OP_PASS_Z_REPLACE ;
124+
125+ // Pack back face bits into the unified format
126+ uint64_t packedStencil = front |
127+ ((back & VRHI_STENCIL_TEST_MASK ) << (VRHI_STENCIL_BACK_TEST_SHIFT - VRHI_STENCIL_TEST_SHIFT )) |
128+ ((back & VRHI_STENCIL_OP_PASS_Z_MASK ) << (VRHI_STENCIL_BACK_OP_PASS_Z_SHIFT - VRHI_STENCIL_OP_PASS_Z_SHIFT ));
129+
130+ nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEFAULT , packedStencil );
131+
132+ EXPECT_TRUE ( ds.stencilEnable );
133+ EXPECT_EQ ( ds.frontFaceStencil .stencilFunc , nvrhi::ComparisonFunc::Always );
134+ EXPECT_EQ ( ds.frontFaceStencil .passOp , nvrhi::StencilOp::Keep );
135+
136+ EXPECT_EQ ( ds.backFaceStencil .stencilFunc , nvrhi::ComparisonFunc::Never );
137+ EXPECT_EQ ( ds.backFaceStencil .passOp , nvrhi::StencilOp::Replace );
138+ }
139+ }
140+
141+ // Test that verifies all stencil mask/shift combinations extract correct values
142+ UTEST_F ( Shader, StencilMaskShiftConsistency )
143+ {
144+ // Test VRHI_STENCIL_TEST_* constants
145+ {
146+ EXPECT_EQ ( (VRHI_STENCIL_TEST_LESS & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 1 );
147+ EXPECT_EQ ( (VRHI_STENCIL_TEST_EQUAL & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 3 );
148+ EXPECT_EQ ( (VRHI_STENCIL_TEST_ALWAYS & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 8 );
149+ }
150+
151+ // Test VRHI_STENCIL_OP_FAIL_S_* constants
152+ {
153+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_KEEP & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 1 );
154+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_REPLACE & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 2 );
155+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_INCR & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 3 );
156+ }
157+
158+ // Test VRHI_STENCIL_OP_FAIL_Z_* constants
159+ {
160+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_Z_KEEP & VRHI_STENCIL_OP_FAIL_Z_MASK ) >> VRHI_STENCIL_OP_FAIL_Z_SHIFT , 1 );
161+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_Z_REPLACE & VRHI_STENCIL_OP_FAIL_Z_MASK ) >> VRHI_STENCIL_OP_FAIL_Z_SHIFT , 2 );
162+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_Z_INCR & VRHI_STENCIL_OP_FAIL_Z_MASK ) >> VRHI_STENCIL_OP_FAIL_Z_SHIFT , 3 );
163+ }
164+
165+ // Test VRHI_STENCIL_OP_PASS_Z_* constants
166+ {
167+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_KEEP & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 1 );
168+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_REPLACE & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 2 );
169+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_INCR & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 3 );
170+ }
124171
125- nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEFAULT , front, back );
172+ // Test FUNC_REF, RMASK, WMASK constants
173+ {
174+ EXPECT_EQ ( (VRHI_STENCIL_FUNC_REF (0x80 ) & VRHI_STENCIL_FUNC_REF_MASK ) >> VRHI_STENCIL_FUNC_REF_SHIFT , 0x80 );
175+ EXPECT_EQ ( (VRHI_STENCIL_FUNC_RMASK (0xFF ) & VRHI_STENCIL_FUNC_RMASK_MASK ) >> VRHI_STENCIL_FUNC_RMASK_SHIFT , 0xFF );
176+ EXPECT_EQ ( (VRHI_STENCIL_FUNC_WMASK (0x7F ) & VRHI_STENCIL_FUNC_WMASK_MASK ) >> VRHI_STENCIL_FUNC_WMASK_SHIFT , 0x7F );
177+ }
178+ }
126179
180+ // Test that verifies unified stencil packing of separate front/back states
181+ UTEST_F ( Shader, StencilUnifiedPacking )
182+ {
183+ // Test case 1: Simple front-only stencil (no back face bits)
184+ {
185+ uint64_t frontOnly = VRHI_STENCIL_TEST_ALWAYS | VRHI_STENCIL_OP_PASS_Z_KEEP ;
186+ nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEFAULT , frontOnly );
187+
127188 EXPECT_TRUE ( ds.stencilEnable );
128189 EXPECT_EQ ( ds.frontFaceStencil .stencilFunc , nvrhi::ComparisonFunc::Always );
129190 EXPECT_EQ ( ds.frontFaceStencil .passOp , nvrhi::StencilOp::Keep );
191+
192+ // Back face should match front when no back bits are set
193+ EXPECT_EQ ( ds.backFaceStencil .stencilFunc , ds.frontFaceStencil .stencilFunc );
194+ EXPECT_EQ ( ds.backFaceStencil .passOp , ds.frontFaceStencil .passOp );
195+ }
130196
197+ // Test case 2: Different front and back (manually packed)
198+ {
199+ uint64_t front = VRHI_STENCIL_TEST_ALWAYS | VRHI_STENCIL_OP_PASS_Z_KEEP ;
200+ uint64_t back = VRHI_STENCIL_TEST_NEVER | VRHI_STENCIL_OP_PASS_Z_REPLACE ;
201+
202+ // Pack back face bits into the unified format (simulating user packing)
203+ uint64_t packedStencil = front |
204+ ((back & VRHI_STENCIL_TEST_MASK ) << (VRHI_STENCIL_BACK_TEST_SHIFT - VRHI_STENCIL_TEST_SHIFT )) |
205+ ((back & VRHI_STENCIL_OP_PASS_Z_MASK ) << (VRHI_STENCIL_BACK_OP_PASS_Z_SHIFT - VRHI_STENCIL_OP_PASS_Z_SHIFT ));
206+
207+ nvrhi::DepthStencilState ds = vhTranslateDepthStencilState ( VRHI_STATE_DEFAULT , packedStencil );
208+
209+ EXPECT_TRUE ( ds.stencilEnable );
210+ EXPECT_EQ ( ds.frontFaceStencil .stencilFunc , nvrhi::ComparisonFunc::Always );
211+ EXPECT_EQ ( ds.frontFaceStencil .passOp , nvrhi::StencilOp::Keep );
131212 EXPECT_EQ ( ds.backFaceStencil .stencilFunc , nvrhi::ComparisonFunc::Never );
132213 EXPECT_EQ ( ds.backFaceStencil .passOp , nvrhi::StencilOp::Replace );
133214 }
134215}
135216
217+ // Test that validates stencil operation constants have correct enum mapping values
218+ UTEST_F ( Shader, StencilConstantValues )
219+ {
220+ // Test all stencil operations - extracted values should match enum indices
221+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_KEEP & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 1 );
222+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_REPLACE & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 2 );
223+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_INCR & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 3 );
224+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_INCRSAT & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 4 );
225+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_DECR & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 5 );
226+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_DECRSAT & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 6 );
227+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_S_INVERT & VRHI_STENCIL_OP_FAIL_S_MASK ) >> VRHI_STENCIL_OP_FAIL_S_SHIFT , 7 );
228+
229+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_Z_KEEP & VRHI_STENCIL_OP_FAIL_Z_MASK ) >> VRHI_STENCIL_OP_FAIL_Z_SHIFT , 1 );
230+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_Z_REPLACE & VRHI_STENCIL_OP_FAIL_Z_MASK ) >> VRHI_STENCIL_OP_FAIL_Z_SHIFT , 2 );
231+ EXPECT_EQ ( (VRHI_STENCIL_OP_FAIL_Z_INCR & VRHI_STENCIL_OP_FAIL_Z_MASK ) >> VRHI_STENCIL_OP_FAIL_Z_SHIFT , 3 );
232+
233+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_KEEP & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 1 );
234+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_REPLACE & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 2 );
235+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_INCR & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 3 );
236+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_INCRSAT & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 4 );
237+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_DECR & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 5 );
238+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_DECRSAT & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 6 );
239+ EXPECT_EQ ( (VRHI_STENCIL_OP_PASS_Z_INVERT & VRHI_STENCIL_OP_PASS_Z_MASK ) >> VRHI_STENCIL_OP_PASS_Z_SHIFT , 7 );
240+
241+ // Verify comparison function constants
242+ EXPECT_EQ ( (VRHI_STENCIL_TEST_LESS & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 1 );
243+ EXPECT_EQ ( (VRHI_STENCIL_TEST_LEQUAL & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 2 );
244+ EXPECT_EQ ( (VRHI_STENCIL_TEST_EQUAL & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 3 );
245+ EXPECT_EQ ( (VRHI_STENCIL_TEST_GEQUAL & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 4 );
246+ EXPECT_EQ ( (VRHI_STENCIL_TEST_GREATER & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 5 );
247+ EXPECT_EQ ( (VRHI_STENCIL_TEST_NOTEQUAL & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 6 );
248+ EXPECT_EQ ( (VRHI_STENCIL_TEST_NEVER & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 7 );
249+ EXPECT_EQ ( (VRHI_STENCIL_TEST_ALWAYS & VRHI_STENCIL_TEST_MASK ) >> VRHI_STENCIL_TEST_SHIFT , 8 );
250+
251+ // Verify reference, read mask, write mask constants
252+ EXPECT_EQ ( (VRHI_STENCIL_FUNC_REF (0x42 ) & VRHI_STENCIL_FUNC_REF_MASK ) >> VRHI_STENCIL_FUNC_REF_SHIFT , 0x42 );
253+ EXPECT_EQ ( (VRHI_STENCIL_FUNC_RMASK (0x55 ) & VRHI_STENCIL_FUNC_RMASK_MASK ) >> VRHI_STENCIL_FUNC_RMASK_SHIFT , 0x55 );
254+ EXPECT_EQ ( (VRHI_STENCIL_FUNC_WMASK (0xAA ) & VRHI_STENCIL_FUNC_WMASK_MASK ) >> VRHI_STENCIL_FUNC_WMASK_SHIFT , 0xAA );
255+ }
256+
136257UTEST_F ( Shader, ValidateBinding )
137258{
138259 vhShaderReflectionResource res;
0 commit comments