1 // Copyright (c) 2020-2022 Valve Corporation
2 // Copyright (c) 2020-2022 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 // Debug Printf Instrumentation Tests.
17
18 #include <string>
19 #include <vector>
20
21 #include "test/opt/assembly_builder.h"
22 #include "test/opt/pass_fixture.h"
23 #include "test/opt/pass_utils.h"
24
25 namespace spvtools {
26 namespace opt {
27 namespace {
28
29 static const std::string kOutputDecorations = R"(
30 ; CHECK: OpDecorate [[output_buffer_type:%inst_printf_OutputBuffer]] Block
31 ; CHECK: OpMemberDecorate [[output_buffer_type]] 0 Offset 0
32 ; CHECK: OpMemberDecorate [[output_buffer_type]] 1 Offset 4
33 ; CHECK: OpMemberDecorate [[output_buffer_type]] 2 Offset 8
34 ; CHECK: OpDecorate [[output_buffer_var:%\w+]] DescriptorSet 7
35 ; CHECK: OpDecorate [[output_buffer_var]] Binding 3
36 )";
37
38 static const std::string kOutputGlobals = R"(
39 ; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %uint %_runtimearr_uint
40 ; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]]
41 ; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer
42 )";
43
44 using InstDebugPrintfTest = PassTest<::testing::Test>;
45
TEST_F(InstDebugPrintfTest,V4Float32)46 TEST_F(InstDebugPrintfTest, V4Float32) {
47 // SamplerState g_sDefault;
48 // Texture2D g_tColor;
49 //
50 // struct PS_INPUT
51 // {
52 // float2 vBaseTexCoord : TEXCOORD0;
53 // };
54 //
55 // struct PS_OUTPUT
56 // {
57 // float4 vDiffuse : SV_Target0;
58 // };
59 //
60 // PS_OUTPUT MainPs(PS_INPUT i)
61 // {
62 // PS_OUTPUT o;
63 //
64 // o.vDiffuse.rgba = g_tColor.Sample(g_sDefault, (i.vBaseTexCoord.xy).xy);
65 // debugPrintfEXT("diffuse: %v4f", o.vDiffuse.rgba);
66 // return o;
67 // }
68
69 const std::string defs =
70 R"(OpCapability Shader
71 OpExtension "SPV_KHR_non_semantic_info"
72 %1 = OpExtInstImport "NonSemantic.DebugPrintf"
73 ; CHECK-NOT: OpExtension "SPV_KHR_non_semantic_info"
74 ; CHECK-NOT: %1 = OpExtInstImport "NonSemantic.DebugPrintf"
75 ; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class"
76 OpMemoryModel Logical GLSL450
77 OpEntryPoint Fragment %2 "MainPs" %3 %4
78 ; CHECK: OpEntryPoint Fragment %2 "MainPs" %3 %4 %gl_FragCoord
79 OpExecutionMode %2 OriginUpperLeft
80 %5 = OpString "Color is %vn"
81 )";
82
83 // clang-format off
84 const std::string decorates =
85 R"(OpDecorate %6 DescriptorSet 0
86 OpDecorate %6 Binding 1
87 OpDecorate %7 DescriptorSet 0
88 OpDecorate %7 Binding 0
89 OpDecorate %3 Location 0
90 OpDecorate %4 Location 0
91 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4
92 )" + kOutputDecorations + R"(
93 ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord
94 )";
95
96 const std::string globals =
97 R"(%void = OpTypeVoid
98 %9 = OpTypeFunction %void
99 %float = OpTypeFloat 32
100 %v2float = OpTypeVector %float 2
101 %v4float = OpTypeVector %float 4
102 %13 = OpTypeImage %float 2D 0 0 0 1 Unknown
103 %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
104 %6 = OpVariable %_ptr_UniformConstant_13 UniformConstant
105 %15 = OpTypeSampler
106 %_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
107 %7 = OpVariable %_ptr_UniformConstant_15 UniformConstant
108 %17 = OpTypeSampledImage %13
109 %_ptr_Input_v2float = OpTypePointer Input %v2float
110 %3 = OpVariable %_ptr_Input_v2float Input
111 %_ptr_Output_v4float = OpTypePointer Output %v4float
112 %4 = OpVariable %_ptr_Output_v4float Output
113 ; CHECK: %uint = OpTypeInt 32 0
114 ; CHECK: [[func_type:%\w+]] = OpTypeFunction %void %uint %uint %uint %uint %uint %uint
115 ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint
116 )" + kOutputGlobals + R"(
117 ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
118 ; CHECK: %bool = OpTypeBool
119 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float
120 ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
121 ; CHECK: %v4uint = OpTypeVector %uint 4
122 )";
123 // clang-format on
124
125 const std::string main =
126 R"(%2 = OpFunction %void None %9
127 %20 = OpLabel
128 %21 = OpLoad %v2float %3
129 %22 = OpLoad %13 %6
130 %23 = OpLoad %15 %7
131 %24 = OpSampledImage %17 %22 %23
132 %25 = OpImageSampleImplicitLod %v4float %24 %21
133 %26 = OpExtInst %void %1 1 %5 %25
134 ; CHECK-NOT: %26 = OpExtInst %void %1 1 %5 %25
135 ; CHECK: %29 = OpCompositeExtract %float %25 0
136 ; CHECK: %30 = OpBitcast %uint %29
137 ; CHECK: %31 = OpCompositeExtract %float %25 1
138 ; CHECK: %32 = OpBitcast %uint %31
139 ; CHECK: %33 = OpCompositeExtract %float %25 2
140 ; CHECK: %34 = OpBitcast %uint %33
141 ; CHECK: %35 = OpCompositeExtract %float %25 3
142 ; CHECK: %36 = OpBitcast %uint %35
143 ; CHECK: %101 = OpFunctionCall %void %inst_printf_stream_write_6 %uint_36 %uint_5 %30 %32 %34 %36
144 ; CHECK: OpBranch %102
145 ; CHECK: %102 = OpLabel
146 OpStore %4 %25
147 OpReturn
148 OpFunctionEnd
149 )";
150
151 const std::string output_func = R"(
152 ; CHECK: %inst_printf_stream_write_6 = OpFunction %void None [[func_type]]
153 ; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint
154 ; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint
155 ; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint
156 ; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint
157 ; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint
158 ; CHECK: [[param_6:%\w+]] = OpFunctionParameter %uint
159 ; CHECK: {{%\w+}} = OpLabel
160 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1
161 ; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_12
162 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12
163 ; CHECK: {{%\w+}} = OpArrayLength %uint %inst_printf_output_buffer 2
164 ; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}}
165 ; CHECK: OpSelectionMerge {{%\w+}} None
166 ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}}
167 ; CHECK: {{%\w+}} = OpLabel
168 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0
169 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
170 ; CHECK: OpStore {{%\w+}} %uint_12
171 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1
172 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
173 ; CHECK: OpStore {{%\w+}} %uint_23
174 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2
175 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
176 ; CHECK: OpStore {{%\w+}} [[param_1]]
177 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3
178 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
179 ; CHECK: OpStore {{%\w+}} %uint_4
180 ; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord
181 ; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}}
182 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0
183 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4
184 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
185 ; CHECK: OpStore {{%\w+}} {{%\w+}}
186 ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1
187 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5
188 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
189 ; CHECK: OpStore {{%\w+}} {{%\w+}}
190 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7
191 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
192 ; CHECK: OpStore {{%\w+}} [[param_2]]
193 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8
194 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
195 ; CHECK: OpStore {{%\w+}} [[param_3]]
196 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9
197 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
198 ; CHECK: OpStore {{%\w+}} [[param_4]]
199 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10
200 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
201 ; CHECK: OpStore {{%\w+}} [[param_5]]
202 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11
203 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}}
204 ; CHECK: OpStore {{%\w+}} [[param_6]]
205 ; CHECK: OpBranch {{%\w+}}
206 ; CHECK: {{%\w+}} = OpLabel
207 ; CHECK: OpReturn
208 ; CHECK: OpFunctionEnd
209 )";
210
211 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
212 SinglePassRunAndMatch<InstDebugPrintfPass>(
213 defs + decorates + globals + main + output_func, true);
214 }
215
216 // TODO(greg-lunarg): Add tests to verify handling of these cases:
217 //
218 // Compute shader
219 // Geometry shader
220 // Tessellation control shader
221 // Tessellation eval shader
222 // Vertex shader
223
224 } // namespace
225 } // namespace opt
226 } // namespace spvtools
227