blob: 919727d7ad008de7a9eeb4fad9fdabb7d286559d [file] [log] [blame]
Robert Konrad45270f62016-08-14 16:21:43 +02001/*
Hans-Kristian Arntzen47044822021-01-14 16:07:49 +01002 * Copyright 2016-2021 Robert Konrad
Jon Leechf2a65542021-05-08 01:47:48 -07003 * SPDX-License-Identifier: Apache-2.0 OR MIT
Robert Konrad41cd8522017-01-26 15:33:49 +01004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010016 *
17 */
18
19/*
20 * At your option, you may choose to accept this material under either:
21 * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
22 * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
Robert Konrad41cd8522017-01-26 15:33:49 +010023 */
Robert Konrad45270f62016-08-14 16:21:43 +020024
25#include "spirv_hlsl.hpp"
Robert Konrad8e9bf1f2016-08-18 12:40:35 +020026#include "GLSL.std.450.h"
Robert Konrada89686822016-08-15 20:33:10 +020027#include <algorithm>
Hans-Kristian Arntzen4375aa32017-08-15 10:12:08 +020028#include <assert.h>
Robert Konrad45270f62016-08-14 16:21:43 +020029
30using namespace spv;
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010031using namespace SPIRV_CROSS_NAMESPACE;
Robert Konrad45270f62016-08-14 16:21:43 +020032using namespace std;
33
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +020034enum class ImageFormatNormalizedState
35{
36 None = 0,
37 Unorm = 1,
38 Snorm = 2
39};
40
41static ImageFormatNormalizedState image_format_to_normalized_state(ImageFormat fmt)
42{
43 switch (fmt)
44 {
45 case ImageFormatR8:
46 case ImageFormatR16:
47 case ImageFormatRg8:
48 case ImageFormatRg16:
49 case ImageFormatRgba8:
50 case ImageFormatRgba16:
51 case ImageFormatRgb10A2:
52 return ImageFormatNormalizedState::Unorm;
53
54 case ImageFormatR8Snorm:
55 case ImageFormatR16Snorm:
56 case ImageFormatRg8Snorm:
57 case ImageFormatRg16Snorm:
58 case ImageFormatRgba8Snorm:
59 case ImageFormatRgba16Snorm:
60 return ImageFormatNormalizedState::Snorm;
61
62 default:
63 break;
64 }
65
66 return ImageFormatNormalizedState::None;
67}
68
Hans-Kristian Arntzena95295c2017-10-24 09:52:12 +020069static unsigned image_format_to_components(ImageFormat fmt)
70{
71 switch (fmt)
72 {
73 case ImageFormatR8:
74 case ImageFormatR16:
75 case ImageFormatR8Snorm:
76 case ImageFormatR16Snorm:
77 case ImageFormatR16f:
78 case ImageFormatR32f:
79 case ImageFormatR8i:
80 case ImageFormatR16i:
81 case ImageFormatR32i:
82 case ImageFormatR8ui:
83 case ImageFormatR16ui:
84 case ImageFormatR32ui:
85 return 1;
86
87 case ImageFormatRg8:
88 case ImageFormatRg16:
89 case ImageFormatRg8Snorm:
90 case ImageFormatRg16Snorm:
91 case ImageFormatRg16f:
92 case ImageFormatRg32f:
93 case ImageFormatRg8i:
94 case ImageFormatRg16i:
95 case ImageFormatRg32i:
96 case ImageFormatRg8ui:
97 case ImageFormatRg16ui:
98 case ImageFormatRg32ui:
99 return 2;
100
101 case ImageFormatR11fG11fB10f:
102 return 3;
103
104 case ImageFormatRgba8:
105 case ImageFormatRgba16:
106 case ImageFormatRgb10A2:
107 case ImageFormatRgba8Snorm:
108 case ImageFormatRgba16Snorm:
109 case ImageFormatRgba16f:
110 case ImageFormatRgba32f:
111 case ImageFormatRgba8i:
112 case ImageFormatRgba16i:
113 case ImageFormatRgba32i:
114 case ImageFormatRgba8ui:
115 case ImageFormatRgba16ui:
116 case ImageFormatRgba32ui:
117 case ImageFormatRgb10a2ui:
118 return 4;
119
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100120 case ImageFormatUnknown:
121 return 4; // Assume 4.
122
Hans-Kristian Arntzena95295c2017-10-24 09:52:12 +0200123 default:
124 SPIRV_CROSS_THROW("Unrecognized typed image format.");
125 }
126}
127
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100128static string image_format_to_type(ImageFormat fmt, SPIRType::BaseType basetype)
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200129{
130 switch (fmt)
131 {
132 case ImageFormatR8:
133 case ImageFormatR16:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100134 if (basetype != SPIRType::Float)
135 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200136 return "unorm float";
137 case ImageFormatRg8:
138 case ImageFormatRg16:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100139 if (basetype != SPIRType::Float)
140 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200141 return "unorm float2";
142 case ImageFormatRgba8:
143 case ImageFormatRgba16:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100144 if (basetype != SPIRType::Float)
145 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200146 return "unorm float4";
147 case ImageFormatRgb10A2:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100148 if (basetype != SPIRType::Float)
149 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200150 return "unorm float4";
151
152 case ImageFormatR8Snorm:
153 case ImageFormatR16Snorm:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100154 if (basetype != SPIRType::Float)
155 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200156 return "snorm float";
157 case ImageFormatRg8Snorm:
158 case ImageFormatRg16Snorm:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100159 if (basetype != SPIRType::Float)
160 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200161 return "snorm float2";
162 case ImageFormatRgba8Snorm:
163 case ImageFormatRgba16Snorm:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100164 if (basetype != SPIRType::Float)
165 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200166 return "snorm float4";
167
168 case ImageFormatR16f:
169 case ImageFormatR32f:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100170 if (basetype != SPIRType::Float)
171 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200172 return "float";
173 case ImageFormatRg16f:
174 case ImageFormatRg32f:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100175 if (basetype != SPIRType::Float)
176 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200177 return "float2";
178 case ImageFormatRgba16f:
179 case ImageFormatRgba32f:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100180 if (basetype != SPIRType::Float)
181 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200182 return "float4";
183
184 case ImageFormatR11fG11fB10f:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100185 if (basetype != SPIRType::Float)
186 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200187 return "float3";
188
189 case ImageFormatR8i:
190 case ImageFormatR16i:
191 case ImageFormatR32i:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100192 if (basetype != SPIRType::Int)
193 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200194 return "int";
195 case ImageFormatRg8i:
196 case ImageFormatRg16i:
197 case ImageFormatRg32i:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100198 if (basetype != SPIRType::Int)
199 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200200 return "int2";
201 case ImageFormatRgba8i:
202 case ImageFormatRgba16i:
203 case ImageFormatRgba32i:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100204 if (basetype != SPIRType::Int)
205 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200206 return "int4";
207
208 case ImageFormatR8ui:
209 case ImageFormatR16ui:
210 case ImageFormatR32ui:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100211 if (basetype != SPIRType::UInt)
212 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200213 return "uint";
214 case ImageFormatRg8ui:
215 case ImageFormatRg16ui:
216 case ImageFormatRg32ui:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100217 if (basetype != SPIRType::UInt)
218 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200219 return "uint2";
220 case ImageFormatRgba8ui:
221 case ImageFormatRgba16ui:
222 case ImageFormatRgba32ui:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100223 if (basetype != SPIRType::UInt)
224 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200225 return "uint4";
226 case ImageFormatRgb10a2ui:
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100227 if (basetype != SPIRType::UInt)
228 SPIRV_CROSS_THROW("Mismatch in image type and base type of image.");
229 return "uint4";
230
231 case ImageFormatUnknown:
232 switch (basetype)
233 {
234 case SPIRType::Float:
235 return "float4";
236 case SPIRType::Int:
237 return "int4";
238 case SPIRType::UInt:
239 return "uint4";
240 default:
241 SPIRV_CROSS_THROW("Unsupported base type for image.");
242 }
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200243
244 default:
245 SPIRV_CROSS_THROW("Unrecognized typed image format.");
246 }
247}
248
Chip Davis2eff4202019-08-04 00:07:20 -0500249string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200250{
251 auto &imagetype = get<SPIRType>(type.image.type);
252 const char *dim = nullptr;
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200253 bool typed_load = false;
Hans-Kristian Arntzene8d5d712017-08-21 10:01:03 +0200254 uint32_t components = 4;
255
Hans-Kristian Arntzen28bf9052020-04-03 11:21:41 +0200256 bool force_image_srv = hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(id, DecorationNonWritable);
257
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200258 switch (type.image.dim)
259 {
260 case Dim1D:
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200261 typed_load = type.image.sampled == 2;
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200262 dim = "1D";
263 break;
264 case Dim2D:
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200265 typed_load = type.image.sampled == 2;
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200266 dim = "2D";
267 break;
268 case Dim3D:
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200269 typed_load = type.image.sampled == 2;
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200270 dim = "3D";
271 break;
272 case DimCube:
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +0200273 if (type.image.sampled == 2)
274 SPIRV_CROSS_THROW("RWTextureCube does not exist in HLSL.");
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200275 dim = "Cube";
276 break;
277 case DimRect:
Hans-Kristian Arntzene8d5d712017-08-21 10:01:03 +0200278 SPIRV_CROSS_THROW("Rectangle texture support is not yet implemented for HLSL."); // TODO
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200279 case DimBuffer:
Hans-Kristian Arntzene8d5d712017-08-21 10:01:03 +0200280 if (type.image.sampled == 1)
281 return join("Buffer<", type_to_glsl(imagetype), components, ">");
282 else if (type.image.sampled == 2)
Chip Davis2eff4202019-08-04 00:07:20 -0500283 {
284 if (interlocked_resources.count(id))
285 return join("RasterizerOrderedBuffer<", image_format_to_type(type.image.format, imagetype.basetype),
286 ">");
Hans-Kristian Arntzen28bf9052020-04-03 11:21:41 +0200287
288 typed_load = !force_image_srv && type.image.sampled == 2;
289
290 const char *rw = force_image_srv ? "" : "RW";
291 return join(rw, "Buffer<",
292 typed_load ? image_format_to_type(type.image.format, imagetype.basetype) :
293 join(type_to_glsl(imagetype), components),
294 ">");
Chip Davis2eff4202019-08-04 00:07:20 -0500295 }
Hans-Kristian Arntzene8d5d712017-08-21 10:01:03 +0200296 else
297 SPIRV_CROSS_THROW("Sampler buffers must be either sampled or unsampled. Cannot deduce in runtime.");
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200298 case DimSubpassData:
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +0100299 dim = "2D";
300 typed_load = false;
301 break;
Hans-Kristian Arntzen08b3c672017-05-09 09:30:30 +0200302 default:
303 SPIRV_CROSS_THROW("Invalid dimension.");
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200304 }
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200305 const char *arrayed = type.image.arrayed ? "Array" : "";
Hans-Kristian Arntzen9aa42a82017-09-20 10:31:05 +0200306 const char *ms = type.image.ms ? "MS" : "";
Hans-Kristian Arntzen28bf9052020-04-03 11:21:41 +0200307 const char *rw = typed_load && !force_image_srv ? "RW" : "";
308
309 if (force_image_srv)
310 typed_load = false;
311
Chip Davis2eff4202019-08-04 00:07:20 -0500312 if (typed_load && interlocked_resources.count(id))
313 rw = "RasterizerOrdered";
Hans-Kristian Arntzen28bf9052020-04-03 11:21:41 +0200314
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +0200315 return join(rw, "Texture", dim, ms, arrayed, "<",
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +0100316 typed_load ? image_format_to_type(type.image.format, imagetype.basetype) :
317 join(type_to_glsl(imagetype), components),
318 ">");
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200319}
320
rdb18893ba2020-10-31 12:06:15 +0100321string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type, uint32_t /*id*/)
Robert Konrad84466312017-04-21 14:54:03 +0200322{
323 auto &imagetype = get<SPIRType>(type.image.type);
324 string res;
325
326 switch (imagetype.basetype)
327 {
328 case SPIRType::Int:
329 res = "i";
330 break;
331 case SPIRType::UInt:
332 res = "u";
333 break;
334 default:
335 break;
336 }
337
338 if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
339 return res + "subpassInput" + (type.image.ms ? "MS" : "");
340
341 // If we're emulating subpassInput with samplers, force sampler2D
342 // so we don't have to specify format.
343 if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
344 {
345 // Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
346 if (type.image.dim == DimBuffer && type.image.sampled == 1)
347 res += "sampler";
348 else
349 res += type.image.sampled == 2 ? "image" : "texture";
350 }
351 else
352 res += "sampler";
353
354 switch (type.image.dim)
355 {
356 case Dim1D:
357 res += "1D";
358 break;
359 case Dim2D:
360 res += "2D";
361 break;
362 case Dim3D:
363 res += "3D";
364 break;
365 case DimCube:
366 res += "CUBE";
367 break;
368
369 case DimBuffer:
370 res += "Buffer";
371 break;
372
373 case DimSubpassData:
374 res += "2D";
375 break;
376 default:
377 SPIRV_CROSS_THROW("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
378 }
379
380 if (type.image.ms)
381 res += "MS";
382 if (type.image.arrayed)
Robert Konrad84466312017-04-21 14:54:03 +0200383 res += "Array";
Robert Konrad84466312017-04-21 14:54:03 +0200384
385 return res;
386}
387
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +0200388string CompilerHLSL::image_type_hlsl(const SPIRType &type, uint32_t id)
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200389{
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +0100390 if (hlsl_options.shader_model <= 30)
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +0200391 return image_type_hlsl_legacy(type, id);
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200392 else
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +0200393 return image_type_hlsl_modern(type, id);
Hans-Kristian Arntzen59ad0842017-05-07 12:53:51 +0200394}
395
Bill Hollingsb41e1482017-05-29 20:45:05 -0400396// The optional id parameter indicates the object whose type we are trying
397// to find the description for. It is optional. Most type descriptions do not
398// depend on a specific object's use of that type.
Hans-Kristian Arntzen978901f2017-06-17 10:54:59 +0200399string CompilerHLSL::type_to_glsl(const SPIRType &type, uint32_t id)
Robert Konrad096d46f2016-08-14 20:28:52 +0200400{
401 // Ignore the pointer type since GLSL doesn't have pointers.
402
403 switch (type.basetype)
404 {
405 case SPIRType::Struct:
406 // Need OpName lookup here to get a "sensible" name for a struct.
407 if (backend.explicit_struct_type)
408 return join("struct ", to_name(type.self));
409 else
410 return to_name(type.self);
411
412 case SPIRType::Image:
413 case SPIRType::SampledImage:
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +0200414 return image_type_hlsl(type, id);
Robert Konrad096d46f2016-08-14 20:28:52 +0200415
416 case SPIRType::Sampler:
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +0200417 return comparison_ids.count(id) ? "SamplerComparisonState" : "SamplerState";
Robert Konrad096d46f2016-08-14 20:28:52 +0200418
419 case SPIRType::Void:
420 return "void";
421
422 default:
423 break;
424 }
425
426 if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
427 {
428 switch (type.basetype)
429 {
430 case SPIRType::Boolean:
431 return "bool";
432 case SPIRType::Int:
433 return backend.basic_int_type;
434 case SPIRType::UInt:
435 return backend.basic_uint_type;
436 case SPIRType::AtomicCounter:
437 return "atomic_uint";
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +0100438 case SPIRType::Half:
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +0200439 if (hlsl_options.enable_16bit_types)
440 return "half";
441 else
442 return "min16float";
443 case SPIRType::Short:
444 if (hlsl_options.enable_16bit_types)
445 return "int16_t";
446 else
447 return "min16int";
448 case SPIRType::UShort:
449 if (hlsl_options.enable_16bit_types)
450 return "uint16_t";
451 else
452 return "min16uint";
Robert Konrad096d46f2016-08-14 20:28:52 +0200453 case SPIRType::Float:
454 return "float";
455 case SPIRType::Double:
456 return "double";
457 case SPIRType::Int64:
Hans-Kristian Arntzene4e47912020-04-21 11:47:45 +0200458 if (hlsl_options.shader_model < 60)
459 SPIRV_CROSS_THROW("64-bit integers only supported in SM 6.0.");
Robert Konrad096d46f2016-08-14 20:28:52 +0200460 return "int64_t";
461 case SPIRType::UInt64:
Hans-Kristian Arntzene4e47912020-04-21 11:47:45 +0200462 if (hlsl_options.shader_model < 60)
463 SPIRV_CROSS_THROW("64-bit integers only supported in SM 6.0.");
Robert Konrad096d46f2016-08-14 20:28:52 +0200464 return "uint64_t";
Konstantin Pail251361b2022-03-15 21:54:29 +0300465 case SPIRType::AccelerationStructure:
466 return "RaytracingAccelerationStructure";
467 case SPIRType::RayQuery:
468 return "RayQuery<RAY_FLAG_NONE>";
Robert Konrad096d46f2016-08-14 20:28:52 +0200469 default:
470 return "???";
471 }
472 }
473 else if (type.vecsize > 1 && type.columns == 1) // Vector builtin
474 {
475 switch (type.basetype)
476 {
477 case SPIRType::Boolean:
Robert Konradf7eecd72017-01-27 17:02:59 +0100478 return join("bool", type.vecsize);
Robert Konrad096d46f2016-08-14 20:28:52 +0200479 case SPIRType::Int:
Robert Konradf7eecd72017-01-27 17:02:59 +0100480 return join("int", type.vecsize);
Robert Konrad096d46f2016-08-14 20:28:52 +0200481 case SPIRType::UInt:
Robert Konradf7eecd72017-01-27 17:02:59 +0100482 return join("uint", type.vecsize);
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +0100483 case SPIRType::Half:
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +0200484 return join(hlsl_options.enable_16bit_types ? "half" : "min16float", type.vecsize);
485 case SPIRType::Short:
486 return join(hlsl_options.enable_16bit_types ? "int16_t" : "min16int", type.vecsize);
487 case SPIRType::UShort:
488 return join(hlsl_options.enable_16bit_types ? "uint16_t" : "min16uint", type.vecsize);
Robert Konrad096d46f2016-08-14 20:28:52 +0200489 case SPIRType::Float:
490 return join("float", type.vecsize);
491 case SPIRType::Double:
492 return join("double", type.vecsize);
493 case SPIRType::Int64:
494 return join("i64vec", type.vecsize);
495 case SPIRType::UInt64:
496 return join("u64vec", type.vecsize);
497 default:
498 return "???";
499 }
500 }
Robert Konrad096d46f2016-08-14 20:28:52 +0200501 else
502 {
503 switch (type.basetype)
504 {
505 case SPIRType::Boolean:
Robert Konradda5f99b2016-08-14 23:54:51 +0200506 return join("bool", type.columns, "x", type.vecsize);
Robert Konrad096d46f2016-08-14 20:28:52 +0200507 case SPIRType::Int:
Robert Konradda5f99b2016-08-14 23:54:51 +0200508 return join("int", type.columns, "x", type.vecsize);
Robert Konrad096d46f2016-08-14 20:28:52 +0200509 case SPIRType::UInt:
Robert Konradda5f99b2016-08-14 23:54:51 +0200510 return join("uint", type.columns, "x", type.vecsize);
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +0100511 case SPIRType::Half:
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +0200512 return join(hlsl_options.enable_16bit_types ? "half" : "min16float", type.columns, "x", type.vecsize);
513 case SPIRType::Short:
514 return join(hlsl_options.enable_16bit_types ? "int16_t" : "min16int", type.columns, "x", type.vecsize);
515 case SPIRType::UShort:
516 return join(hlsl_options.enable_16bit_types ? "uint16_t" : "min16uint", type.columns, "x", type.vecsize);
Robert Konrad096d46f2016-08-14 20:28:52 +0200517 case SPIRType::Float:
Robert Konradda5f99b2016-08-14 23:54:51 +0200518 return join("float", type.columns, "x", type.vecsize);
Robert Konrad096d46f2016-08-14 20:28:52 +0200519 case SPIRType::Double:
Robert Konradda5f99b2016-08-14 23:54:51 +0200520 return join("double", type.columns, "x", type.vecsize);
Robert Konrade9cd04e2016-08-14 22:02:38 +0200521 // Matrix types not supported for int64/uint64.
Robert Konrad096d46f2016-08-14 20:28:52 +0200522 default:
523 return "???";
524 }
525 }
526}
527
Robert Konrad02fd8e92016-08-14 17:58:56 +0200528void CompilerHLSL::emit_header()
529{
Robert Konrad02fd8e92016-08-14 17:58:56 +0200530 for (auto &header : header_lines)
531 statement(header);
Robert Konrade9cd04e2016-08-14 22:02:38 +0200532
Robert Konrad1a48d7d2016-08-18 12:54:22 +0200533 if (header_lines.size() > 0)
534 {
535 statement("");
536 }
Robert Konrad02fd8e92016-08-14 17:58:56 +0200537}
538
Robert Konrad80fcf552016-08-14 21:33:32 +0200539void CompilerHLSL::emit_interface_block_globally(const SPIRVariable &var)
540{
Robert Konrad80fcf552016-08-14 21:33:32 +0200541 add_resource_name(var.self);
Hans-Kristian Arntzena0a582d2017-03-20 09:52:18 +0100542
543 // The global copies of I/O variables should not contain interpolation qualifiers.
544 // These are emitted inside the interface structs.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200545 auto &flags = ir.meta[var.self].decoration.decoration_flags;
Hans-Kristian Arntzena0a582d2017-03-20 09:52:18 +0100546 auto old_flags = flags;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100547 flags.reset();
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100548 statement("static ", variable_decl(var), ";");
Hans-Kristian Arntzena0a582d2017-03-20 09:52:18 +0100549 flags = old_flags;
Robert Konrad80fcf552016-08-14 21:33:32 +0200550}
551
Hans-Kristian Arntzenbcf23032017-02-24 11:15:34 +0100552const char *CompilerHLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
553{
554 // Input and output variables are handled specially in HLSL backend.
555 // The variables are declared as global, private variables, and do not need any qualifiers.
556 if (var.storage == StorageClassUniformConstant || var.storage == StorageClassUniform ||
557 var.storage == StorageClassPushConstant)
558 {
559 return "uniform ";
560 }
561
562 return "";
563}
564
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100565void CompilerHLSL::emit_builtin_outputs_in_struct()
566{
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +0100567 auto &execution = get_entry_point();
568
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +0100569 bool legacy = hlsl_options.shader_model <= 30;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100570 active_output_builtins.for_each_bit([&](uint32_t i) {
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100571 const char *type = nullptr;
572 const char *semantic = nullptr;
573 auto builtin = static_cast<BuiltIn>(i);
574 switch (builtin)
575 {
576 case BuiltInPosition:
Hans-Kristian Arntzenb8115ff2021-05-07 13:15:55 +0200577 type = is_position_invariant() && backend.support_precise_qualifier ? "precise float4" : "float4";
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100578 semantic = legacy ? "POSITION" : "SV_Position";
579 break;
580
Tomek Ponitkaba58f782020-07-23 19:09:43 +0200581 case BuiltInSampleMask:
582 if (hlsl_options.shader_model < 41 || execution.model != ExecutionModelFragment)
583 SPIRV_CROSS_THROW("Sample Mask output is only supported in PS 4.1 or higher.");
584 type = "uint";
585 semantic = "SV_Coverage";
586 break;
587
Hans-Kristian Arntzena4aa89e2017-03-07 13:51:33 +0100588 case BuiltInFragDepth:
589 type = "float";
Hans-Kristian Arntzen4e5c8d72018-11-12 10:29:59 +0100590 if (legacy)
591 {
592 semantic = "DEPTH";
593 }
594 else
595 {
596 if (hlsl_options.shader_model >= 50 && execution.flags.get(ExecutionModeDepthGreater))
597 semantic = "SV_DepthGreaterEqual";
598 else if (hlsl_options.shader_model >= 50 && execution.flags.get(ExecutionModeDepthLess))
599 semantic = "SV_DepthLessEqual";
600 else
601 semantic = "SV_Depth";
602 }
Hans-Kristian Arntzena4aa89e2017-03-07 13:51:33 +0100603 break;
604
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +0100605 case BuiltInClipDistance:
606 // HLSL is a bit weird here, use SV_ClipDistance0, SV_ClipDistance1 and so on with vectors.
607 for (uint32_t clip = 0; clip < clip_distance_count; clip += 4)
608 {
609 uint32_t to_declare = clip_distance_count - clip;
610 if (to_declare > 4)
611 to_declare = 4;
612
613 uint32_t semantic_index = clip / 4;
614
615 static const char *types[] = { "float", "float2", "float3", "float4" };
Hans-Kristian Arntzen4543dac2018-02-23 13:13:02 +0100616 statement(types[to_declare - 1], " ", builtin_to_glsl(builtin, StorageClassOutput), semantic_index,
617 " : SV_ClipDistance", semantic_index, ";");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +0100618 }
619 break;
620
621 case BuiltInCullDistance:
622 // HLSL is a bit weird here, use SV_CullDistance0, SV_CullDistance1 and so on with vectors.
623 for (uint32_t cull = 0; cull < cull_distance_count; cull += 4)
624 {
625 uint32_t to_declare = cull_distance_count - cull;
626 if (to_declare > 4)
627 to_declare = 4;
628
629 uint32_t semantic_index = cull / 4;
630
631 static const char *types[] = { "float", "float2", "float3", "float4" };
Hans-Kristian Arntzen4543dac2018-02-23 13:13:02 +0100632 statement(types[to_declare - 1], " ", builtin_to_glsl(builtin, StorageClassOutput), semantic_index,
633 " : SV_CullDistance", semantic_index, ";");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +0100634 }
635 break;
636
Hans-Kristian Arntzen17d88ca2017-05-04 10:10:30 +0200637 case BuiltInPointSize:
638 // If point_size_compat is enabled, just ignore PointSize.
639 // PointSize does not exist in HLSL, but some code bases might want to be able to use these shaders,
640 // even if it means working around the missing feature.
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +0100641 if (hlsl_options.point_size_compat)
Hans-Kristian Arntzen17d88ca2017-05-04 10:10:30 +0200642 break;
643 else
644 SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
645
Laura Hermanns65431442022-04-28 16:42:03 -0400646 case BuiltInLayer:
647 if (hlsl_options.shader_model < 50 || get_entry_point().model != ExecutionModelGeometry)
iwubcodea6976d52022-05-21 00:52:23 -0500648 SPIRV_CROSS_THROW("Render target array index output is only supported in GS 5.0 or higher.");
Laura Hermanns65431442022-04-28 16:42:03 -0400649 type = "uint";
iwubcodea6976d52022-05-21 00:52:23 -0500650 semantic = "SV_RenderTargetArrayIndex";
Laura Hermanns65431442022-04-28 16:42:03 -0400651 break;
652
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100653 default:
654 SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100655 }
656
657 if (type && semantic)
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +0200658 statement(type, " ", builtin_to_glsl(builtin, StorageClassOutput), " : ", semantic, ";");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100659 });
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100660}
661
662void CompilerHLSL::emit_builtin_inputs_in_struct()
663{
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +0100664 bool legacy = hlsl_options.shader_model <= 30;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100665 active_input_builtins.for_each_bit([&](uint32_t i) {
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100666 const char *type = nullptr;
667 const char *semantic = nullptr;
668 auto builtin = static_cast<BuiltIn>(i);
669 switch (builtin)
670 {
671 case BuiltInFragCoord:
672 type = "float4";
Hans-Kristian Arntzena4aa89e2017-03-07 13:51:33 +0100673 semantic = legacy ? "VPOS" : "SV_Position";
674 break;
675
Hans-Kristian Arntzen5e9b53e2017-12-06 11:01:32 +0100676 case BuiltInVertexId:
Hans-Kristian Arntzena4aa89e2017-03-07 13:51:33 +0100677 case BuiltInVertexIndex:
678 if (legacy)
679 SPIRV_CROSS_THROW("Vertex index not supported in SM 3.0 or lower.");
680 type = "uint";
681 semantic = "SV_VertexID";
682 break;
683
skksdkfak54c00b62022-04-07 12:56:53 +0300684 case BuiltInPrimitiveId:
685 type = "uint";
686 semantic = "SV_PrimitiveID";
687 break;
688
Hans-Kristian Arntzen5e9b53e2017-12-06 11:01:32 +0100689 case BuiltInInstanceId:
Hans-Kristian Arntzena4aa89e2017-03-07 13:51:33 +0100690 case BuiltInInstanceIndex:
691 if (legacy)
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +0100692 SPIRV_CROSS_THROW("Instance index not supported in SM 3.0 or lower.");
Hans-Kristian Arntzena4aa89e2017-03-07 13:51:33 +0100693 type = "uint";
694 semantic = "SV_InstanceID";
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100695 break;
696
Robert Konrade7b02582017-03-24 13:58:39 +0100697 case BuiltInSampleId:
698 if (legacy)
699 SPIRV_CROSS_THROW("Sample ID not supported in SM 3.0 or lower.");
700 type = "uint";
701 semantic = "SV_SampleIndex";
702 break;
703
Tomek Ponitkaba58f782020-07-23 19:09:43 +0200704 case BuiltInSampleMask:
705 if (hlsl_options.shader_model < 50 || get_entry_point().model != ExecutionModelFragment)
706 SPIRV_CROSS_THROW("Sample Mask input is only supported in PS 5.0 or higher.");
707 type = "uint";
708 semantic = "SV_Coverage";
709 break;
710
Hans-Kristian Arntzene2bb5b82017-08-15 09:34:30 +0200711 case BuiltInGlobalInvocationId:
712 type = "uint3";
713 semantic = "SV_DispatchThreadID";
714 break;
715
716 case BuiltInLocalInvocationId:
717 type = "uint3";
718 semantic = "SV_GroupThreadID";
719 break;
720
721 case BuiltInLocalInvocationIndex:
722 type = "uint";
723 semantic = "SV_GroupIndex";
724 break;
725
726 case BuiltInWorkgroupId:
727 type = "uint3";
728 semantic = "SV_GroupID";
729 break;
730
Hans-Kristian Arntzen843e34b2018-02-15 12:42:56 +0100731 case BuiltInFrontFacing:
732 type = "bool";
733 semantic = "SV_IsFrontFace";
734 break;
735
Pedro J. Estébanez2ea1c9b2022-04-15 10:39:42 +0200736 case BuiltInViewIndex:
737 if (hlsl_options.shader_model < 61 || (get_entry_point().model != ExecutionModelVertex && get_entry_point().model != ExecutionModelFragment))
738 SPIRV_CROSS_THROW("View Index input is only supported in VS and PS 6.1 or higher.");
739 type = "uint";
740 semantic = "SV_ViewID";
741 break;
742
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +0100743 case BuiltInNumWorkgroups:
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +0200744 case BuiltInSubgroupSize:
745 case BuiltInSubgroupLocalInvocationId:
746 case BuiltInSubgroupEqMask:
747 case BuiltInSubgroupLtMask:
748 case BuiltInSubgroupLeMask:
749 case BuiltInSubgroupGtMask:
750 case BuiltInSubgroupGeMask:
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +0100751 // Handled specially.
752 break;
753
Pedro J. Estébanez278a4c82022-03-04 09:09:08 +0100754 case BuiltInHelperInvocation:
Pedro J. Estébanezc4f9e4f2022-03-04 13:05:26 +0100755 if (hlsl_options.shader_model < 50 || get_entry_point().model != ExecutionModelFragment)
Pedro J. Estébanez278a4c82022-03-04 09:09:08 +0100756 SPIRV_CROSS_THROW("Helper Invocation input is only supported in PS 5.0 or higher.");
757 break;
758
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +0100759 case BuiltInClipDistance:
760 // HLSL is a bit weird here, use SV_ClipDistance0, SV_ClipDistance1 and so on with vectors.
761 for (uint32_t clip = 0; clip < clip_distance_count; clip += 4)
762 {
763 uint32_t to_declare = clip_distance_count - clip;
764 if (to_declare > 4)
765 to_declare = 4;
766
767 uint32_t semantic_index = clip / 4;
768
769 static const char *types[] = { "float", "float2", "float3", "float4" };
Hans-Kristian Arntzen4543dac2018-02-23 13:13:02 +0100770 statement(types[to_declare - 1], " ", builtin_to_glsl(builtin, StorageClassInput), semantic_index,
771 " : SV_ClipDistance", semantic_index, ";");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +0100772 }
773 break;
774
775 case BuiltInCullDistance:
776 // HLSL is a bit weird here, use SV_CullDistance0, SV_CullDistance1 and so on with vectors.
777 for (uint32_t cull = 0; cull < cull_distance_count; cull += 4)
778 {
779 uint32_t to_declare = cull_distance_count - cull;
780 if (to_declare > 4)
781 to_declare = 4;
782
783 uint32_t semantic_index = cull / 4;
784
785 static const char *types[] = { "float", "float2", "float3", "float4" };
Hans-Kristian Arntzen4543dac2018-02-23 13:13:02 +0100786 statement(types[to_declare - 1], " ", builtin_to_glsl(builtin, StorageClassInput), semantic_index,
787 " : SV_CullDistance", semantic_index, ";");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +0100788 }
789 break;
790
Hans-Kristian Arntzenf6d08e62018-02-23 15:56:25 +0100791 case BuiltInPointCoord:
792 // PointCoord is not supported, but provide a way to just ignore that, similar to PointSize.
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +0100793 if (hlsl_options.point_coord_compat)
Hans-Kristian Arntzenf6d08e62018-02-23 15:56:25 +0100794 break;
795 else
796 SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
797
Laura Hermanns65431442022-04-28 16:42:03 -0400798 case BuiltInLayer:
799 if (hlsl_options.shader_model < 50 || get_entry_point().model != ExecutionModelFragment)
iwubcodea6976d52022-05-21 00:52:23 -0500800 SPIRV_CROSS_THROW("Render target array index input is only supported in PS 5.0 or higher.");
Laura Hermanns65431442022-04-28 16:42:03 -0400801 type = "uint";
iwubcodea6976d52022-05-21 00:52:23 -0500802 semantic = "SV_RenderTargetArrayIndex";
Laura Hermanns65431442022-04-28 16:42:03 -0400803 break;
804
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100805 default:
806 SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100807 }
808
809 if (type && semantic)
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +0200810 statement(type, " ", builtin_to_glsl(builtin, StorageClassInput), " : ", semantic, ";");
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100811 });
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100812}
813
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100814uint32_t CompilerHLSL::type_to_consumed_locations(const SPIRType &type) const
815{
816 // TODO: Need to verify correctness.
817 uint32_t elements = 0;
818
819 if (type.basetype == SPIRType::Struct)
820 {
821 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
822 elements += type_to_consumed_locations(get<SPIRType>(type.member_types[i]));
823 }
824 else
825 {
826 uint32_t array_multiplier = 1;
827 for (uint32_t i = 0; i < uint32_t(type.array.size()); i++)
828 {
829 if (type.array_size_literal[i])
830 array_multiplier *= type.array[i];
831 else
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +0200832 array_multiplier *= evaluate_constant_u32(type.array[i]);
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100833 }
834 elements += array_multiplier * type.columns;
835 }
836 return elements;
837}
838
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100839string CompilerHLSL::to_interpolation_qualifiers(const Bitset &flags)
Hans-Kristian Arntzenb8bda452017-03-20 09:48:43 +0100840{
841 string res;
842 //if (flags & (1ull << DecorationSmooth))
843 // res += "linear ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100844 if (flags.get(DecorationFlat))
Hans-Kristian Arntzenb8bda452017-03-20 09:48:43 +0100845 res += "nointerpolation ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100846 if (flags.get(DecorationNoPerspective))
Hans-Kristian Arntzenb8bda452017-03-20 09:48:43 +0100847 res += "noperspective ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100848 if (flags.get(DecorationCentroid))
Hans-Kristian Arntzenb8bda452017-03-20 09:48:43 +0100849 res += "centroid ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100850 if (flags.get(DecorationPatch))
Hans-Kristian Arntzenb8bda452017-03-20 09:48:43 +0100851 res += "patch "; // Seems to be different in actual HLSL.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100852 if (flags.get(DecorationSample))
Hans-Kristian Arntzenb8bda452017-03-20 09:48:43 +0100853 res += "sample ";
Hans-Kristian Arntzenb8115ff2021-05-07 13:15:55 +0200854 if (flags.get(DecorationInvariant) && backend.support_precise_qualifier)
855 res += "precise "; // Not supported?
Hans-Kristian Arntzenb8bda452017-03-20 09:48:43 +0100856
857 return res;
858}
859
Ashley Harriscc2d2902019-04-12 13:54:58 +0930860std::string CompilerHLSL::to_semantic(uint32_t location, ExecutionModel em, StorageClass sc)
Hans-Kristian Arntzen56716a92017-11-13 09:52:00 +0100861{
Ashley Harriscc2d2902019-04-12 13:54:58 +0930862 if (em == ExecutionModelVertex && sc == StorageClassInput)
863 {
864 // We have a vertex attribute - we should look at remapping it if the user provided
865 // vertex attribute hints.
866 for (auto &attribute : remap_vertex_attributes)
867 if (attribute.location == location)
868 return attribute.semantic;
869 }
Hans-Kristian Arntzen56716a92017-11-13 09:52:00 +0100870
Ashley Harriscc2d2902019-04-12 13:54:58 +0930871 // Not a vertex attribute, or no remap_vertex_attributes entry.
872 return join("TEXCOORD", location);
Hans-Kristian Arntzen56716a92017-11-13 09:52:00 +0100873}
874
Hans-Kristian Arntzen9a304fe2021-01-04 11:16:58 +0100875std::string CompilerHLSL::to_initializer_expression(const SPIRVariable &var)
876{
877 // We cannot emit static const initializer for block constants for practical reasons,
878 // so just inline the initializer.
879 // FIXME: There is a theoretical problem here if someone tries to composite extract
880 // into this initializer since we don't declare it properly, but that is somewhat non-sensical.
881 auto &type = get<SPIRType>(var.basetype);
882 bool is_block = has_decoration(type.self, DecorationBlock);
883 auto *c = maybe_get<SPIRConstant>(var.initializer);
884 if (is_block && c)
885 return constant_expression(*c);
886 else
887 return CompilerGLSL::to_initializer_expression(var);
888}
889
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +0200890void CompilerHLSL::emit_interface_block_member_in_struct(const SPIRVariable &var, uint32_t member_index,
891 uint32_t location,
892 std::unordered_set<uint32_t> &active_locations)
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +0100893{
Ashley Harriscc2d2902019-04-12 13:54:58 +0930894 auto &execution = get_entry_point();
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +0200895 auto type = get<SPIRType>(var.basetype);
896 auto semantic = to_semantic(location, execution.model, var.storage);
897 auto mbr_name = join(to_name(type.self), "_", to_member_name(type, member_index));
898 auto &mbr_type = get<SPIRType>(type.member_types[member_index]);
Ashley Harriscc2d2902019-04-12 13:54:58 +0930899
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +0200900 statement(to_interpolation_qualifiers(get_member_decoration_bitset(type.self, member_index)),
901 type_to_glsl(mbr_type),
902 " ", mbr_name, type_to_array_glsl(mbr_type),
903 " : ", semantic, ";");
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +0100904
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +0200905 // Structs and arrays should consume more locations.
906 uint32_t consumed_locations = type_to_consumed_locations(mbr_type);
907 for (uint32_t i = 0; i < consumed_locations; i++)
908 active_locations.insert(location + i);
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +0100909}
910
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100911void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unordered_set<uint32_t> &active_locations)
Robert Konrad02fd8e92016-08-14 17:58:56 +0200912{
913 auto &execution = get_entry_point();
crosire0cdfbe42018-09-11 20:29:24 +0200914 auto type = get<SPIRType>(var.basetype);
Robert Konrad02fd8e92016-08-14 17:58:56 +0200915
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100916 string binding;
Hans-Kristian Arntzen4f88f972017-11-13 09:46:45 +0100917 bool use_location_number = true;
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +0100918 bool legacy = hlsl_options.shader_model <= 30;
Robert Konradd2b29c92016-08-14 23:09:06 +0200919 if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
Robert Konrad02fd8e92016-08-14 17:58:56 +0200920 {
Hans-Kristian Arntzena365ff12019-01-11 10:03:45 +0100921 // Dual-source blending is achieved in HLSL by emitting to SV_Target0 and 1.
922 uint32_t index = get_decoration(var.self, DecorationIndex);
923 uint32_t location = get_decoration(var.self, DecorationLocation);
924
925 if (index != 0 && location != 0)
926 SPIRV_CROSS_THROW("Dual-source blending is only supported on MRT #0 in HLSL.");
927
928 binding = join(legacy ? "COLOR" : "SV_Target", location + index);
Hans-Kristian Arntzen4f88f972017-11-13 09:46:45 +0100929 use_location_number = false;
crosire0cdfbe42018-09-11 20:29:24 +0200930 if (legacy) // COLOR must be a four-component vector on legacy shader model targets (HLSL ERR_COLOR_4COMP)
931 type.vecsize = 4;
Robert Konradda5f99b2016-08-14 23:54:51 +0200932 }
Robert Konrade9cd04e2016-08-14 22:02:38 +0200933
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100934 const auto get_vacant_location = [&]() -> uint32_t {
935 for (uint32_t i = 0; i < 64; i++)
936 if (!active_locations.count(i))
937 return i;
938 SPIRV_CROSS_THROW("All locations from 0 to 63 are exhausted.");
939 };
940
Hans-Kristian Arntzeneb58f672017-10-05 16:31:52 +0200941 bool need_matrix_unroll = var.storage == StorageClassInput && execution.model == ExecutionModelVertex;
942
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100943 auto name = to_name(var.self);
Hans-Kristian Arntzen4f88f972017-11-13 09:46:45 +0100944 if (use_location_number)
Robert Konradd2b29c92016-08-14 23:09:06 +0200945 {
Hans-Kristian Arntzen4f88f972017-11-13 09:46:45 +0100946 uint32_t location_number;
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100947
948 // If an explicit location exists, use it with TEXCOORD[N] semantic.
949 // Otherwise, pick a vacant location.
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +0200950 if (has_decoration(var.self, DecorationLocation))
951 location_number = get_decoration(var.self, DecorationLocation);
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100952 else
Hans-Kristian Arntzen4f88f972017-11-13 09:46:45 +0100953 location_number = get_vacant_location();
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100954
Amer Koleci7216d132017-11-06 20:10:04 +0100955 // Allow semantic remap if specified.
Ashley Harriscc2d2902019-04-12 13:54:58 +0930956 auto semantic = to_semantic(location_number, execution.model, var.storage);
Hans-Kristian Arntzen4f88f972017-11-13 09:46:45 +0100957
Hans-Kristian Arntzeneb58f672017-10-05 16:31:52 +0200958 if (need_matrix_unroll && type.columns > 1)
Robert Konrad4a0267e2016-09-23 23:56:37 +0200959 {
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100960 if (!type.array.empty())
961 SPIRV_CROSS_THROW("Arrays of matrices used as input/output. This is not supported.");
962
963 // Unroll matrices.
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100964 for (uint32_t i = 0; i < type.columns; i++)
Robert Konradffc590e2016-09-24 19:31:05 +0200965 {
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100966 SPIRType newtype = type;
967 newtype.columns = 1;
Hans-Kristian Arntzenb3344172020-11-03 11:18:32 +0100968
969 string effective_semantic;
970 if (hlsl_options.flatten_matrix_vertex_input_semantics)
971 effective_semantic = to_semantic(location_number, execution.model, var.storage);
972 else
973 effective_semantic = join(semantic, "_", i);
974
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100975 statement(to_interpolation_qualifiers(get_decoration_bitset(var.self)),
Hans-Kristian Arntzenb3344172020-11-03 11:18:32 +0100976 variable_decl(newtype, join(name, "_", i)), " : ", effective_semantic, ";");
Hans-Kristian Arntzen4f88f972017-11-13 09:46:45 +0100977 active_locations.insert(location_number++);
Robert Konradffc590e2016-09-24 19:31:05 +0200978 }
Robert Konrad4a0267e2016-09-23 23:56:37 +0200979 }
980 else
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100981 {
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100982 statement(to_interpolation_qualifiers(get_decoration_bitset(var.self)), variable_decl(type, name), " : ",
Hans-Kristian Arntzenf4861422017-11-13 09:52:35 +0100983 semantic, ";");
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100984
985 // Structs and arrays should consume more locations.
986 uint32_t consumed_locations = type_to_consumed_locations(type);
987 for (uint32_t i = 0; i < consumed_locations; i++)
Hans-Kristian Arntzen4f88f972017-11-13 09:46:45 +0100988 active_locations.insert(location_number + i);
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100989 }
Robert Konradd2b29c92016-08-14 23:09:06 +0200990 }
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100991 else
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +0100992 statement(variable_decl(type, name), " : ", binding, ";");
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +0100993}
994
Hans-Kristian Arntzen5e9b53e2017-12-06 11:01:32 +0100995std::string CompilerHLSL::builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage)
996{
997 switch (builtin)
998 {
999 case BuiltInVertexId:
1000 return "gl_VertexID";
1001 case BuiltInInstanceId:
1002 return "gl_InstanceID";
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01001003 case BuiltInNumWorkgroups:
1004 {
1005 if (!num_workgroups_builtin)
msiglreithd096f5c2017-11-27 16:00:56 +01001006 SPIRV_CROSS_THROW("NumWorkgroups builtin is used, but remap_num_workgroups_builtin() was not called. "
1007 "Cannot emit code for this builtin.");
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01001008
1009 auto &var = get<SPIRVariable>(num_workgroups_builtin);
1010 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02001011 auto ret = join(to_name(num_workgroups_builtin), "_", get_member_name(type.self, 0));
1012 ParsedIR::sanitize_underscores(ret);
1013 return ret;
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01001014 }
Hans-Kristian Arntzenf6d08e62018-02-23 15:56:25 +01001015 case BuiltInPointCoord:
1016 // Crude hack, but there is no real alternative. This path is only enabled if point_coord_compat is set.
1017 return "float2(0.5f, 0.5f)";
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02001018 case BuiltInSubgroupLocalInvocationId:
1019 return "WaveGetLaneIndex()";
1020 case BuiltInSubgroupSize:
1021 return "WaveGetLaneCount()";
Pedro J. Estébanez278a4c82022-03-04 09:09:08 +01001022 case BuiltInHelperInvocation:
1023 return "IsHelperLane()";
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02001024
Hans-Kristian Arntzen5e9b53e2017-12-06 11:01:32 +01001025 default:
1026 return CompilerGLSL::builtin_to_glsl(builtin, storage);
1027 }
1028}
1029
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001030void CompilerHLSL::emit_builtin_variables()
1031{
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001032 Bitset builtins = active_input_builtins;
1033 builtins.merge_or(active_output_builtins);
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001034
Hans-Kristian Arntzena2a44d92019-01-11 10:32:14 +01001035 bool need_base_vertex_info = false;
1036
Hans-Kristian Arntzena1c784f2021-01-04 11:58:50 +01001037 std::unordered_map<uint32_t, ID> builtin_to_initializer;
1038 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
1039 if (!is_builtin_variable(var) || var.storage != StorageClassOutput || !var.initializer)
1040 return;
1041
1042 auto *c = this->maybe_get<SPIRConstant>(var.initializer);
1043 if (!c)
1044 return;
1045
1046 auto &type = this->get<SPIRType>(var.basetype);
1047 if (type.basetype == SPIRType::Struct)
1048 {
1049 uint32_t member_count = uint32_t(type.member_types.size());
1050 for (uint32_t i = 0; i < member_count; i++)
1051 {
1052 if (has_member_decoration(type.self, i, DecorationBuiltIn))
1053 {
1054 builtin_to_initializer[get_member_decoration(type.self, i, DecorationBuiltIn)] =
1055 c->subconstants[i];
1056 }
1057 }
1058 }
1059 else if (has_decoration(var.self, DecorationBuiltIn))
1060 builtin_to_initializer[get_decoration(var.self, DecorationBuiltIn)] = var.initializer;
1061 });
1062
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001063 // Emit global variables for the interface variables which are statically used by the shader.
1064 builtins.for_each_bit([&](uint32_t i) {
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001065 const char *type = nullptr;
1066 auto builtin = static_cast<BuiltIn>(i);
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01001067 uint32_t array_size = 0;
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001068
Hans-Kristian Arntzena1c784f2021-01-04 11:58:50 +01001069 string init_expr;
1070 auto init_itr = builtin_to_initializer.find(builtin);
1071 if (init_itr != builtin_to_initializer.end())
1072 init_expr = join(" = ", to_expression(init_itr->second));
1073
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001074 switch (builtin)
1075 {
1076 case BuiltInFragCoord:
1077 case BuiltInPosition:
1078 type = "float4";
1079 break;
1080
Hans-Kristian Arntzena4aa89e2017-03-07 13:51:33 +01001081 case BuiltInFragDepth:
1082 type = "float";
1083 break;
1084
Hans-Kristian Arntzen5e9b53e2017-12-06 11:01:32 +01001085 case BuiltInVertexId:
Hans-Kristian Arntzena4aa89e2017-03-07 13:51:33 +01001086 case BuiltInVertexIndex:
1087 case BuiltInInstanceIndex:
Hans-Kristian Arntzena2a44d92019-01-11 10:32:14 +01001088 type = "int";
1089 if (hlsl_options.support_nonzero_base_vertex_base_instance)
1090 need_base_vertex_info = true;
1091 break;
1092
1093 case BuiltInInstanceId:
Robert Konrade7b02582017-03-24 13:58:39 +01001094 case BuiltInSampleId:
Hans-Kristian Arntzena4aa89e2017-03-07 13:51:33 +01001095 type = "int";
1096 break;
1097
Hans-Kristian Arntzen17d88ca2017-05-04 10:10:30 +02001098 case BuiltInPointSize:
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01001099 if (hlsl_options.point_size_compat)
Hans-Kristian Arntzen17d88ca2017-05-04 10:10:30 +02001100 {
1101 // Just emit the global variable, it will be ignored.
1102 type = "float";
1103 break;
1104 }
1105 else
1106 SPIRV_CROSS_THROW(join("Unsupported builtin in HLSL: ", unsigned(builtin)));
1107
Hans-Kristian Arntzene2bb5b82017-08-15 09:34:30 +02001108 case BuiltInGlobalInvocationId:
1109 case BuiltInLocalInvocationId:
1110 case BuiltInWorkgroupId:
1111 type = "uint3";
1112 break;
1113
1114 case BuiltInLocalInvocationIndex:
1115 type = "uint";
1116 break;
1117
Hans-Kristian Arntzen843e34b2018-02-15 12:42:56 +01001118 case BuiltInFrontFacing:
1119 type = "bool";
1120 break;
1121
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01001122 case BuiltInNumWorkgroups:
Hans-Kristian Arntzenf6d08e62018-02-23 15:56:25 +01001123 case BuiltInPointCoord:
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01001124 // Handled specially.
1125 break;
1126
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02001127 case BuiltInSubgroupLocalInvocationId:
1128 case BuiltInSubgroupSize:
1129 if (hlsl_options.shader_model < 60)
1130 SPIRV_CROSS_THROW("Need SM 6.0 for Wave ops.");
1131 break;
1132
1133 case BuiltInSubgroupEqMask:
1134 case BuiltInSubgroupLtMask:
1135 case BuiltInSubgroupLeMask:
1136 case BuiltInSubgroupGtMask:
1137 case BuiltInSubgroupGeMask:
1138 if (hlsl_options.shader_model < 60)
1139 SPIRV_CROSS_THROW("Need SM 6.0 for Wave ops.");
1140 type = "uint4";
1141 break;
1142
Pedro J. Estébanez278a4c82022-03-04 09:09:08 +01001143 case BuiltInHelperInvocation:
1144 if (hlsl_options.shader_model < 50)
1145 SPIRV_CROSS_THROW("Need SM 5.0 for Helper Invocation.");
1146 break;
1147
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01001148 case BuiltInClipDistance:
1149 array_size = clip_distance_count;
1150 type = "float";
1151 break;
1152
1153 case BuiltInCullDistance:
1154 array_size = cull_distance_count;
1155 type = "float";
1156 break;
1157
Tomek Ponitkaba58f782020-07-23 19:09:43 +02001158 case BuiltInSampleMask:
1159 type = "int";
1160 break;
1161
skksdkfak54c00b62022-04-07 12:56:53 +03001162 case BuiltInPrimitiveId:
Pedro J. Estébanez2ea1c9b2022-04-15 10:39:42 +02001163 case BuiltInViewIndex:
Laura Hermanns65431442022-04-28 16:42:03 -04001164 case BuiltInLayer:
skksdkfak54c00b62022-04-07 12:56:53 +03001165 type = "uint";
1166 break;
1167
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001168 default:
1169 SPIRV_CROSS_THROW(join("Unsupported builtin in HLSL: ", unsigned(builtin)));
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001170 }
1171
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001172 StorageClass storage = active_input_builtins.get(i) ? StorageClassInput : StorageClassOutput;
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02001173
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001174 if (type)
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01001175 {
1176 if (array_size)
Hans-Kristian Arntzena1c784f2021-01-04 11:58:50 +01001177 statement("static ", type, " ", builtin_to_glsl(builtin, storage), "[", array_size, "]", init_expr, ";");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01001178 else
Hans-Kristian Arntzena1c784f2021-01-04 11:58:50 +01001179 statement("static ", type, " ", builtin_to_glsl(builtin, storage), init_expr, ";");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01001180 }
Tomek Ponitkaba58f782020-07-23 19:09:43 +02001181
1182 // SampleMask can be both in and out with sample builtin, in this case we have already
1183 // declared the input variable and we need to add the output one now.
1184 if (builtin == BuiltInSampleMask && storage == StorageClassInput && this->active_output_builtins.get(i))
1185 {
Hans-Kristian Arntzena1c784f2021-01-04 11:58:50 +01001186 statement("static ", type, " ", this->builtin_to_glsl(builtin, StorageClassOutput), init_expr, ";");
Tomek Ponitkaba58f782020-07-23 19:09:43 +02001187 }
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001188 });
Hans-Kristian Arntzena2a44d92019-01-11 10:32:14 +01001189
1190 if (need_base_vertex_info)
1191 {
1192 statement("cbuffer SPIRV_Cross_VertexInfo");
1193 begin_scope();
1194 statement("int SPIRV_Cross_BaseVertex;");
1195 statement("int SPIRV_Cross_BaseInstance;");
1196 end_scope_decl();
1197 statement("");
1198 }
Robert Konrad02fd8e92016-08-14 17:58:56 +02001199}
1200
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01001201void CompilerHLSL::emit_composite_constants()
1202{
1203 // HLSL cannot declare structs or arrays inline, so we must move them out to
1204 // global constants directly.
1205 bool emitted = false;
1206
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001207 ir.for_each_typed_id<SPIRConstant>([&](uint32_t, SPIRConstant &c) {
1208 if (c.specialization)
1209 return;
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01001210
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01001211 auto &type = this->get<SPIRType>(c.constant_type);
Hans-Kristian Arntzen9a304fe2021-01-04 11:16:58 +01001212
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001213 if (type.basetype == SPIRType::Struct && is_builtin_type(type))
1214 return;
1215
1216 if (type.basetype == SPIRType::Struct || !type.array.empty())
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001217 {
Hans-Kristian Arntzenac461402022-01-18 12:39:16 +01001218 add_resource_name(c.self);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001219 auto name = to_name(c.self);
1220 statement("static const ", variable_decl(type, name), " = ", constant_expression(c), ";");
1221 emitted = true;
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01001222 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001223 });
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01001224
1225 if (emitted)
1226 statement("");
1227}
1228
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001229void CompilerHLSL::emit_specialization_constants_and_structs()
Hans-Kristian Arntzen98c76ee2017-07-29 22:12:19 +02001230{
1231 bool emitted = false;
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001232 SpecializationConstant wg_x, wg_y, wg_z;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001233 ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001234
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001235 std::unordered_set<TypeID> io_block_types;
1236 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
1237 auto &type = this->get<SPIRType>(var.basetype);
1238 if ((var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
1239 !var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
1240 interface_variable_exists_in_entry_point(var.self) &&
1241 has_decoration(type.self, DecorationBlock))
1242 {
1243 io_block_types.insert(type.self);
1244 }
1245 });
1246
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +02001247 auto loop_lock = ir.create_loop_hard_lock();
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001248 for (auto &id_ : ir.ids_for_constant_or_type)
Hans-Kristian Arntzen98c76ee2017-07-29 22:12:19 +02001249 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001250 auto &id = ir.ids[id_];
1251
Hans-Kristian Arntzen98c76ee2017-07-29 22:12:19 +02001252 if (id.get_type() == TypeConstant)
1253 {
1254 auto &c = id.get<SPIRConstant>();
Hans-Kristian Arntzen62db5352018-11-01 11:22:14 +01001255
Hans-Kristian Arntzen84f8c992017-09-29 10:13:45 +02001256 if (c.self == workgroup_size_id)
Hans-Kristian Arntzen62db5352018-11-01 11:22:14 +01001257 {
1258 statement("static const uint3 gl_WorkGroupSize = ",
Hans-Kristian Arntzen6e99fcf2018-11-01 11:23:33 +01001259 constant_expression(get<SPIRConstant>(workgroup_size_id)), ";");
Hans-Kristian Arntzen62db5352018-11-01 11:22:14 +01001260 emitted = true;
1261 }
1262 else if (c.specialization)
1263 {
1264 auto &type = get<SPIRType>(c.constant_type);
Hans-Kristian Arntzen48b5a902022-01-18 12:31:28 +01001265 add_resource_name(c.self);
Hans-Kristian Arntzen62db5352018-11-01 11:22:14 +01001266 auto name = to_name(c.self);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02001267
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01001268 if (has_decoration(c.self, DecorationSpecId))
1269 {
1270 // HLSL does not support specialization constants, so fallback to macros.
1271 c.specialization_constant_macro_name =
1272 constant_value_macro_name(get_decoration(c.self, DecorationSpecId));
Hans-Kristian Arntzen98c76ee2017-07-29 22:12:19 +02001273
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01001274 statement("#ifndef ", c.specialization_constant_macro_name);
1275 statement("#define ", c.specialization_constant_macro_name, " ", constant_expression(c));
1276 statement("#endif");
1277 statement("static const ", variable_decl(type, name), " = ", c.specialization_constant_macro_name, ";");
1278 }
1279 else
1280 statement("static const ", variable_decl(type, name), " = ", constant_expression(c), ";");
1281
Hans-Kristian Arntzen62db5352018-11-01 11:22:14 +01001282 emitted = true;
1283 }
Hans-Kristian Arntzen98c76ee2017-07-29 22:12:19 +02001284 }
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02001285 else if (id.get_type() == TypeConstantOp)
1286 {
1287 auto &c = id.get<SPIRConstantOp>();
1288 auto &type = get<SPIRType>(c.basetype);
Hans-Kristian Arntzen48b5a902022-01-18 12:31:28 +01001289 add_resource_name(c.self);
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02001290 auto name = to_name(c.self);
1291 statement("static const ", variable_decl(type, name), " = ", constant_op_expression(c), ";");
Hans-Kristian Arntzen00d542e2018-11-01 11:49:32 +01001292 emitted = true;
Hans-Kristian Arntzen991b6552018-05-15 14:20:16 +02001293 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001294 else if (id.get_type() == TypeType)
1295 {
1296 auto &type = id.get<SPIRType>();
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001297 bool is_non_io_block = has_decoration(type.self, DecorationBlock) &&
1298 io_block_types.count(type.self) == 0;
1299 bool is_buffer_block = has_decoration(type.self, DecorationBufferBlock);
1300 if (type.basetype == SPIRType::Struct && type.array.empty() &&
1301 !type.pointer && !is_non_io_block && !is_buffer_block)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001302 {
1303 if (emitted)
1304 statement("");
1305 emitted = false;
1306
1307 emit_struct(type);
1308 }
1309 }
Hans-Kristian Arntzen98c76ee2017-07-29 22:12:19 +02001310 }
1311
1312 if (emitted)
1313 statement("");
1314}
1315
Hans-Kristian Arntzen0617b982018-05-15 11:16:35 +02001316void CompilerHLSL::replace_illegal_names()
1317{
Pascal Muetschardaced6052018-05-04 14:53:32 -07001318 static const unordered_set<string> keywords = {
1319 // Additional HLSL specific keywords.
Hans-Kristian Arntzen10a76312022-04-28 14:56:13 +02001320 // From https://docs.microsoft.com/en-US/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-keywords
1321 "AppendStructuredBuffer", "asm", "asm_fragment",
1322 "BlendState", "bool", "break", "Buffer", "ByteAddressBuffer",
1323 "case", "cbuffer", "centroid", "class", "column_major", "compile",
1324 "compile_fragment", "CompileShader", "const", "continue", "ComputeShader",
1325 "ConsumeStructuredBuffer",
1326 "default", "DepthStencilState", "DepthStencilView", "discard", "do",
1327 "double", "DomainShader", "dword",
1328 "else", "export", "false", "float", "for", "fxgroup",
1329 "GeometryShader", "groupshared", "half", "HullShader",
1330 "if", "in", "inline", "inout", "InputPatch", "int", "interface",
1331 "line", "lineadj", "linear", "LineStream",
1332 "matrix", "min16float", "min10float", "min16int", "min16uint",
1333 "namespace", "nointerpolation", "noperspective", "NULL",
1334 "out", "OutputPatch",
1335 "packoffset", "pass", "pixelfragment", "PixelShader", "point",
1336 "PointStream", "precise", "RasterizerState", "RenderTargetView",
1337 "return", "register", "row_major", "RWBuffer", "RWByteAddressBuffer",
1338 "RWStructuredBuffer", "RWTexture1D", "RWTexture1DArray", "RWTexture2D",
1339 "RWTexture2DArray", "RWTexture3D", "sample", "sampler", "SamplerState",
1340 "SamplerComparisonState", "shared", "snorm", "stateblock", "stateblock_state",
1341 "static", "string", "struct", "switch", "StructuredBuffer", "tbuffer",
1342 "technique", "technique10", "technique11", "texture", "Texture1D",
1343 "Texture1DArray", "Texture2D", "Texture2DArray", "Texture2DMS", "Texture2DMSArray",
1344 "Texture3D", "TextureCube", "TextureCubeArray", "true", "typedef", "triangle",
1345 "triangleadj", "TriangleStream", "uint", "uniform", "unorm", "unsigned",
1346 "vector", "vertexfragment", "VertexShader", "void", "volatile", "while",
Pascal Muetschardaced6052018-05-04 14:53:32 -07001347 };
1348
Hans-Kristian Arntzenf79c1e22020-01-16 10:28:54 +01001349 CompilerGLSL::replace_illegal_names(keywords);
Pascal Muetschardaced6052018-05-04 14:53:32 -07001350 CompilerGLSL::replace_illegal_names();
1351}
1352
Hans-Kristian Arntzene81c1b12020-02-08 13:39:50 +01001353void CompilerHLSL::declare_undefined_values()
1354{
1355 bool emitted = false;
1356 ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02001357 auto &type = this->get<SPIRType>(undef.basetype);
1358 // OpUndef can be void for some reason ...
1359 if (type.basetype == SPIRType::Void)
1360 return;
1361
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01001362 string initializer;
Hans-Kristian Arntzen18d03b32020-09-04 09:29:44 +02001363 if (options.force_zero_initialized_variables && type_can_zero_initialize(type))
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01001364 initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
1365
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01001366 statement("static ", variable_decl(type, to_name(undef.self), undef.self), initializer, ";");
Hans-Kristian Arntzene81c1b12020-02-08 13:39:50 +01001367 emitted = true;
1368 });
1369
1370 if (emitted)
1371 statement("");
1372}
1373
Robert Konrad02fd8e92016-08-14 17:58:56 +02001374void CompilerHLSL::emit_resources()
1375{
1376 auto &execution = get_entry_point();
Robert Konrade9cd04e2016-08-14 22:02:38 +02001377
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01001378 replace_illegal_names();
1379
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001380 emit_specialization_constants_and_structs();
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01001381 emit_composite_constants();
1382
Robert Konrad02fd8e92016-08-14 17:58:56 +02001383 bool emitted = false;
1384
Robert Konrad99469f02017-01-24 09:17:43 +01001385 // Output UBOs and SSBOs
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001386 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01001387 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001388
1389 bool is_block_storage = type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform;
1390 bool has_block_flags = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
1391 ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock);
1392
1393 if (var.storage != StorageClassFunction && type.pointer && is_block_storage && !is_hidden_variable(var) &&
1394 has_block_flags)
Robert Konrad99469f02017-01-24 09:17:43 +01001395 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001396 emit_buffer_block(var);
1397 emitted = true;
Robert Konrad99469f02017-01-24 09:17:43 +01001398 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001399 });
Robert Konrad99469f02017-01-24 09:17:43 +01001400
1401 // Output push constant blocks
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001402 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01001403 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001404 if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassPushConstant &&
1405 !is_hidden_variable(var))
Robert Konrad99469f02017-01-24 09:17:43 +01001406 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001407 emit_push_constant_block(var);
1408 emitted = true;
Robert Konrad99469f02017-01-24 09:17:43 +01001409 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001410 });
Robert Konrad99469f02017-01-24 09:17:43 +01001411
Hans-Kristian Arntzen7af0a5f2022-02-28 12:09:40 +01001412 if (execution.model == ExecutionModelVertex && hlsl_options.shader_model <= 30 &&
1413 active_output_builtins.get(BuiltInPosition))
Robert Konrad95a716f2016-08-16 00:27:39 +02001414 {
1415 statement("uniform float4 gl_HalfPixel;");
1416 emitted = true;
1417 }
1418
Minmin Gonge3ebfda2018-11-10 13:33:15 -08001419 bool skip_separate_image_sampler = !combined_image_samplers.empty() || hlsl_options.shader_model <= 30;
1420
Robert Konrad02fd8e92016-08-14 17:58:56 +02001421 // Output Uniform Constants (values, samplers, images, etc).
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001422 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01001423 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001424
1425 // If we're remapping separate samplers and images, only emit the combined samplers.
1426 if (skip_separate_image_sampler)
Robert Konrad02fd8e92016-08-14 17:58:56 +02001427 {
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001428 // Sampler buffers are always used without a sampler, and they will also work in regular D3D.
1429 bool sampler_buffer = type.basetype == SPIRType::Image && type.image.dim == DimBuffer;
1430 bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
1431 bool separate_sampler = type.basetype == SPIRType::Sampler;
1432 if (!sampler_buffer && (separate_image || separate_sampler))
1433 return;
Robert Konrad02fd8e92016-08-14 17:58:56 +02001434 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001435
1436 if (var.storage != StorageClassFunction && !is_builtin_variable(var) && !var.remapped_variable &&
Hans-Kristian Arntzenea02a0c2021-01-22 13:48:16 +01001437 type.pointer && (type.storage == StorageClassUniformConstant || type.storage == StorageClassAtomicCounter) &&
1438 !is_hidden_variable(var))
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001439 {
1440 emit_uniform(var);
1441 emitted = true;
1442 }
1443 });
Robert Konrad02fd8e92016-08-14 17:58:56 +02001444
1445 if (emitted)
1446 statement("");
1447 emitted = false;
1448
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001449 // Emit builtin input and output variables here.
1450 emit_builtin_variables();
1451
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001452 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01001453 auto &type = this->get<SPIRType>(var.basetype);
Robert Konrad80fcf552016-08-14 21:33:32 +02001454
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001455 if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer &&
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001456 (var.storage == StorageClassInput || var.storage == StorageClassOutput) && !is_builtin_variable(var) &&
1457 interface_variable_exists_in_entry_point(var.self))
1458 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001459 // Builtin variables are handled separately.
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001460 emit_interface_block_globally(var);
1461 emitted = true;
Robert Konrad80fcf552016-08-14 21:33:32 +02001462 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001463 });
Robert Konrad80fcf552016-08-14 21:33:32 +02001464
1465 if (emitted)
1466 statement("");
1467 emitted = false;
1468
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01001469 require_input = false;
1470 require_output = false;
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +01001471 unordered_set<uint32_t> active_inputs;
1472 unordered_set<uint32_t> active_outputs;
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001473
1474 struct IOVariable
1475 {
1476 const SPIRVariable *var;
1477 uint32_t location;
1478 uint32_t block_member_index;
1479 bool block;
1480 };
1481
1482 SmallVector<IOVariable> input_variables;
1483 SmallVector<IOVariable> output_variables;
1484
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001485 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01001486 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001487 bool block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001488
1489 if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
1490 return;
1491
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001492 if (!var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001493 interface_variable_exists_in_entry_point(var.self))
Robert Konrad02fd8e92016-08-14 17:58:56 +02001494 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001495 if (block)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001496 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001497 for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001498 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001499 uint32_t location = get_declared_member_location(var, i, false);
1500 if (var.storage == StorageClassInput)
1501 input_variables.push_back({ &var, location, i, true });
1502 else
1503 output_variables.push_back({ &var, location, i, true });
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001504 }
1505 }
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001506 else
1507 {
1508 uint32_t location = get_decoration(var.self, DecorationLocation);
1509 if (var.storage == StorageClassInput)
1510 input_variables.push_back({ &var, location, 0, false });
1511 else
1512 output_variables.push_back({ &var, location, 0, false });
1513 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001514 }
1515 });
Robert Konrad02fd8e92016-08-14 17:58:56 +02001516
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001517 const auto variable_compare = [&](const IOVariable &a, const IOVariable &b) -> bool {
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +01001518 // Sort input and output variables based on, from more robust to less robust:
1519 // - Location
1520 // - Variable has a location
1521 // - Name comparison
1522 // - Variable has a name
1523 // - Fallback: ID
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001524 bool has_location_a = a.block || has_decoration(a.var->self, DecorationLocation);
1525 bool has_location_b = b.block || has_decoration(b.var->self, DecorationLocation);
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +01001526
1527 if (has_location_a && has_location_b)
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001528 return a.location < b.location;
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +01001529 else if (has_location_a && !has_location_b)
1530 return true;
1531 else if (!has_location_a && has_location_b)
1532 return false;
1533
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001534 const auto &name1 = to_name(a.var->self);
1535 const auto &name2 = to_name(b.var->self);
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +01001536
1537 if (name1.empty() && name2.empty())
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001538 return a.var->self < b.var->self;
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +01001539 else if (name1.empty())
1540 return true;
1541 else if (name2.empty())
1542 return false;
1543
1544 return name1.compare(name2) < 0;
1545 };
1546
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001547 auto input_builtins = active_input_builtins;
1548 input_builtins.clear(BuiltInNumWorkgroups);
1549 input_builtins.clear(BuiltInPointCoord);
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02001550 input_builtins.clear(BuiltInSubgroupSize);
1551 input_builtins.clear(BuiltInSubgroupLocalInvocationId);
1552 input_builtins.clear(BuiltInSubgroupEqMask);
1553 input_builtins.clear(BuiltInSubgroupLtMask);
1554 input_builtins.clear(BuiltInSubgroupLeMask);
1555 input_builtins.clear(BuiltInSubgroupGtMask);
1556 input_builtins.clear(BuiltInSubgroupGeMask);
1557
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001558 if (!input_variables.empty() || !input_builtins.empty())
Robert Konrad02fd8e92016-08-14 17:58:56 +02001559 {
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001560 require_input = true;
1561 statement("struct SPIRV_Cross_Input");
1562
1563 begin_scope();
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +01001564 sort(input_variables.begin(), input_variables.end(), variable_compare);
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001565 for (auto &var : input_variables)
1566 {
1567 if (var.block)
1568 emit_interface_block_member_in_struct(*var.var, var.block_member_index, var.location, active_inputs);
1569 else
1570 emit_interface_block_in_struct(*var.var, active_inputs);
1571 }
Robert Konrade7b02582017-03-24 13:58:39 +01001572 emit_builtin_inputs_in_struct();
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001573 end_scope_decl();
1574 statement("");
Robert Konrad02fd8e92016-08-14 17:58:56 +02001575 }
Robert Konrad02fd8e92016-08-14 17:58:56 +02001576
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001577 if (!output_variables.empty() || !active_output_builtins.empty())
Robert Konrada89686822016-08-15 20:33:10 +02001578 {
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001579 require_output = true;
1580 statement("struct SPIRV_Cross_Output");
1581
1582 begin_scope();
Hans-Kristian Arntzen61c31c62017-03-07 13:27:04 +01001583 sort(output_variables.begin(), output_variables.end(), variable_compare);
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02001584 for (auto &var : output_variables)
1585 {
1586 if (var.block)
1587 emit_interface_block_member_in_struct(*var.var, var.block_member_index, var.location, active_outputs);
1588 else
1589 emit_interface_block_in_struct(*var.var, active_outputs);
1590 }
Robert Konrade7b02582017-03-24 13:58:39 +01001591 emit_builtin_outputs_in_struct();
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01001592 end_scope_decl();
1593 statement("");
Robert Konrad4a0267e2016-09-23 23:56:37 +02001594 }
Robert Konrad02fd8e92016-08-14 17:58:56 +02001595
1596 // Global variables.
1597 for (auto global : global_variables)
1598 {
1599 auto &var = get<SPIRVariable>(global);
Hans-Kristian Arntzenea02a0c2021-01-22 13:48:16 +01001600 if (is_hidden_variable(var, true))
1601 continue;
1602
Robert Konrad02fd8e92016-08-14 17:58:56 +02001603 if (var.storage != StorageClassOutput)
1604 {
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01001605 if (!variable_is_lut(var))
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02001606 {
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01001607 add_resource_name(var.self);
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02001608
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01001609 const char *storage = nullptr;
1610 switch (var.storage)
1611 {
1612 case StorageClassWorkgroup:
1613 storage = "groupshared";
1614 break;
1615
1616 default:
1617 storage = "static";
1618 break;
1619 }
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +01001620
1621 string initializer;
1622 if (options.force_zero_initialized_variables && var.storage == StorageClassPrivate &&
1623 !var.initializer && !var.static_expression && type_can_zero_initialize(get_variable_data_type(var)))
1624 {
1625 initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(var)));
1626 }
1627 statement(storage, " ", variable_decl(var), initializer, ";");
1628
Hans-Kristian Arntzen3e584f22019-02-06 10:38:18 +01001629 emitted = true;
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02001630 }
Robert Konrad02fd8e92016-08-14 17:58:56 +02001631 }
1632 }
1633
1634 if (emitted)
1635 statement("");
Robert Konrad1a48d7d2016-08-18 12:54:22 +02001636
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02001637 declare_undefined_values();
1638
Robert Konrad1a48d7d2016-08-18 12:54:22 +02001639 if (requires_op_fmod)
1640 {
Hans-Kristian Arntzend4727fe2017-10-06 13:21:42 +02001641 static const char *types[] = {
Hans-Kristian Arntzence18d4c2017-11-17 13:38:29 +01001642 "float",
1643 "float2",
1644 "float3",
1645 "float4",
Hans-Kristian Arntzend4727fe2017-10-06 13:21:42 +02001646 };
1647
1648 for (auto &type : types)
1649 {
1650 statement(type, " mod(", type, " x, ", type, " y)");
1651 begin_scope();
1652 statement("return x - y * floor(x / y);");
1653 end_scope();
1654 statement("");
1655 }
Robert Konrad1a48d7d2016-08-18 12:54:22 +02001656 }
Robert Konradfd9b5892017-04-20 13:37:38 +02001657
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02001658 emit_texture_size_variants(required_texture_size_variants.srv, "4", false, "");
1659 for (uint32_t norm = 0; norm < 3; norm++)
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02001660 {
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02001661 for (uint32_t comp = 0; comp < 4; comp++)
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02001662 {
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02001663 static const char *qualifiers[] = { "", "unorm ", "snorm " };
1664 static const char *vecsizes[] = { "", "2", "3", "4" };
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02001665 emit_texture_size_variants(required_texture_size_variants.uav[norm][comp], vecsizes[comp], true,
1666 qualifiers[norm]);
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02001667 }
1668 }
Hans-Kristian Arntzen6c7c6802017-11-27 14:24:30 +01001669
1670 if (requires_fp16_packing)
1671 {
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01001672 // HLSL does not pack into a single word sadly :(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001673 statement("uint spvPackHalf2x16(float2 value)");
Hans-Kristian Arntzen6c7c6802017-11-27 14:24:30 +01001674 begin_scope();
1675 statement("uint2 Packed = f32tof16(value);");
1676 statement("return Packed.x | (Packed.y << 16);");
1677 end_scope();
1678 statement("");
1679
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001680 statement("float2 spvUnpackHalf2x16(uint value)");
Hans-Kristian Arntzen6c7c6802017-11-27 14:24:30 +01001681 begin_scope();
1682 statement("return f16tof32(uint2(value & 0xffff, value >> 16));");
1683 end_scope();
1684 statement("");
1685 }
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01001686
Asuka55dfbea2020-04-17 22:46:06 +08001687 if (requires_uint2_packing)
1688 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001689 statement("uint64_t spvPackUint2x32(uint2 value)");
Asuka55dfbea2020-04-17 22:46:06 +08001690 begin_scope();
Hans-Kristian Arntzen7b9cba72020-04-21 11:48:37 +02001691 statement("return (uint64_t(value.y) << 32) | uint64_t(value.x);");
Asuka55dfbea2020-04-17 22:46:06 +08001692 end_scope();
1693 statement("");
1694
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001695 statement("uint2 spvUnpackUint2x32(uint64_t value)");
Asuka55dfbea2020-04-17 22:46:06 +08001696 begin_scope();
1697 statement("uint2 Unpacked;");
1698 statement("Unpacked.x = uint(value & 0xffffffff);");
1699 statement("Unpacked.y = uint(value >> 32);");
Hans-Kristian Arntzen7b9cba72020-04-21 11:48:37 +02001700 statement("return Unpacked;");
Asuka55dfbea2020-04-17 22:46:06 +08001701 end_scope();
1702 statement("");
1703 }
1704
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01001705 if (requires_explicit_fp16_packing)
1706 {
1707 // HLSL does not pack into a single word sadly :(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001708 statement("uint spvPackFloat2x16(min16float2 value)");
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01001709 begin_scope();
1710 statement("uint2 Packed = f32tof16(value);");
1711 statement("return Packed.x | (Packed.y << 16);");
1712 end_scope();
1713 statement("");
1714
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001715 statement("min16float2 spvUnpackFloat2x16(uint value)");
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01001716 begin_scope();
1717 statement("return min16float2(f16tof32(uint2(value & 0xffff, value >> 16)));");
1718 end_scope();
1719 statement("");
1720 }
1721
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01001722 // HLSL does not seem to have builtins for these operation, so roll them by hand ...
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01001723 if (requires_unorm8_packing)
1724 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001725 statement("uint spvPackUnorm4x8(float4 value)");
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01001726 begin_scope();
1727 statement("uint4 Packed = uint4(round(saturate(value) * 255.0));");
1728 statement("return Packed.x | (Packed.y << 8) | (Packed.z << 16) | (Packed.w << 24);");
1729 end_scope();
1730 statement("");
1731
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001732 statement("float4 spvUnpackUnorm4x8(uint value)");
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01001733 begin_scope();
1734 statement("uint4 Packed = uint4(value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, value >> 24);");
1735 statement("return float4(Packed) / 255.0;");
1736 end_scope();
1737 statement("");
1738 }
1739
1740 if (requires_snorm8_packing)
1741 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001742 statement("uint spvPackSnorm4x8(float4 value)");
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01001743 begin_scope();
1744 statement("int4 Packed = int4(round(clamp(value, -1.0, 1.0) * 127.0)) & 0xff;");
1745 statement("return uint(Packed.x | (Packed.y << 8) | (Packed.z << 16) | (Packed.w << 24));");
1746 end_scope();
1747 statement("");
1748
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001749 statement("float4 spvUnpackSnorm4x8(uint value)");
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01001750 begin_scope();
1751 statement("int SignedValue = int(value);");
1752 statement("int4 Packed = int4(SignedValue << 24, SignedValue << 16, SignedValue << 8, SignedValue) >> 24;");
1753 statement("return clamp(float4(Packed) / 127.0, -1.0, 1.0);");
1754 end_scope();
1755 statement("");
1756 }
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01001757
1758 if (requires_unorm16_packing)
1759 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001760 statement("uint spvPackUnorm2x16(float2 value)");
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01001761 begin_scope();
1762 statement("uint2 Packed = uint2(round(saturate(value) * 65535.0));");
1763 statement("return Packed.x | (Packed.y << 16);");
1764 end_scope();
1765 statement("");
1766
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001767 statement("float2 spvUnpackUnorm2x16(uint value)");
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01001768 begin_scope();
1769 statement("uint2 Packed = uint2(value & 0xffff, value >> 16);");
1770 statement("return float2(Packed) / 65535.0;");
1771 end_scope();
1772 statement("");
1773 }
1774
1775 if (requires_snorm16_packing)
1776 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001777 statement("uint spvPackSnorm2x16(float2 value)");
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01001778 begin_scope();
1779 statement("int2 Packed = int2(round(clamp(value, -1.0, 1.0) * 32767.0)) & 0xffff;");
1780 statement("return uint(Packed.x | (Packed.y << 16));");
1781 end_scope();
1782 statement("");
1783
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001784 statement("float2 spvUnpackSnorm2x16(uint value)");
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01001785 begin_scope();
1786 statement("int SignedValue = int(value);");
1787 statement("int2 Packed = int2(SignedValue << 16, SignedValue) >> 16;");
1788 statement("return clamp(float2(Packed) / 32767.0, -1.0, 1.0);");
1789 end_scope();
1790 statement("");
1791 }
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01001792
1793 if (requires_bitfield_insert)
1794 {
1795 static const char *types[] = { "uint", "uint2", "uint3", "uint4" };
1796 for (auto &type : types)
1797 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001798 statement(type, " spvBitfieldInsert(", type, " Base, ", type, " Insert, uint Offset, uint Count)");
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01001799 begin_scope();
1800 statement("uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31));");
1801 statement("return (Base & ~Mask) | ((Insert << Offset) & Mask);");
1802 end_scope();
1803 statement("");
1804 }
1805 }
1806
1807 if (requires_bitfield_extract)
1808 {
1809 static const char *unsigned_types[] = { "uint", "uint2", "uint3", "uint4" };
1810 for (auto &type : unsigned_types)
1811 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001812 statement(type, " spvBitfieldUExtract(", type, " Base, uint Offset, uint Count)");
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01001813 begin_scope();
1814 statement("uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1);");
1815 statement("return (Base >> Offset) & Mask;");
1816 end_scope();
1817 statement("");
1818 }
1819
1820 // In this overload, we will have to do sign-extension, which we will emulate by shifting up and down.
1821 static const char *signed_types[] = { "int", "int2", "int3", "int4" };
1822 for (auto &type : signed_types)
1823 {
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001824 statement(type, " spvBitfieldSExtract(", type, " Base, int Offset, int Count)");
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01001825 begin_scope();
1826 statement("int Mask = Count == 32 ? -1 : ((1 << Count) - 1);");
1827 statement(type, " Masked = (Base >> Offset) & Mask;");
1828 statement("int ExtendShift = (32 - Count) & 31;");
1829 statement("return (Masked << ExtendShift) >> ExtendShift;");
1830 end_scope();
1831 statement("");
1832 }
1833 }
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001834
1835 if (requires_inverse_2x2)
1836 {
1837 statement("// Returns the inverse of a matrix, by using the algorithm of calculating the classical");
1838 statement("// adjoint and dividing by the determinant. The contents of the matrix are changed.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001839 statement("float2x2 spvInverse(float2x2 m)");
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001840 begin_scope();
1841 statement("float2x2 adj; // The adjoint matrix (inverse after dividing by determinant)");
1842 statement_no_indent("");
1843 statement("// Create the transpose of the cofactors, as the classical adjoint of the matrix.");
1844 statement("adj[0][0] = m[1][1];");
1845 statement("adj[0][1] = -m[0][1];");
1846 statement_no_indent("");
1847 statement("adj[1][0] = -m[1][0];");
1848 statement("adj[1][1] = m[0][0];");
1849 statement_no_indent("");
1850 statement("// Calculate the determinant as a combination of the cofactors of the first row.");
1851 statement("float det = (adj[0][0] * m[0][0]) + (adj[0][1] * m[1][0]);");
1852 statement_no_indent("");
1853 statement("// Divide the classical adjoint matrix by the determinant.");
1854 statement("// If determinant is zero, matrix is not invertable, so leave it unchanged.");
1855 statement("return (det != 0.0f) ? (adj * (1.0f / det)) : m;");
1856 end_scope();
1857 statement("");
1858 }
1859
1860 if (requires_inverse_3x3)
1861 {
1862 statement("// Returns the determinant of a 2x2 matrix.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001863 statement("float spvDet2x2(float a1, float a2, float b1, float b2)");
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001864 begin_scope();
1865 statement("return a1 * b2 - b1 * a2;");
1866 end_scope();
1867 statement_no_indent("");
1868 statement("// Returns the inverse of a matrix, by using the algorithm of calculating the classical");
1869 statement("// adjoint and dividing by the determinant. The contents of the matrix are changed.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001870 statement("float3x3 spvInverse(float3x3 m)");
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001871 begin_scope();
1872 statement("float3x3 adj; // The adjoint matrix (inverse after dividing by determinant)");
1873 statement_no_indent("");
1874 statement("// Create the transpose of the cofactors, as the classical adjoint of the matrix.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001875 statement("adj[0][0] = spvDet2x2(m[1][1], m[1][2], m[2][1], m[2][2]);");
1876 statement("adj[0][1] = -spvDet2x2(m[0][1], m[0][2], m[2][1], m[2][2]);");
1877 statement("adj[0][2] = spvDet2x2(m[0][1], m[0][2], m[1][1], m[1][2]);");
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001878 statement_no_indent("");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001879 statement("adj[1][0] = -spvDet2x2(m[1][0], m[1][2], m[2][0], m[2][2]);");
1880 statement("adj[1][1] = spvDet2x2(m[0][0], m[0][2], m[2][0], m[2][2]);");
1881 statement("adj[1][2] = -spvDet2x2(m[0][0], m[0][2], m[1][0], m[1][2]);");
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001882 statement_no_indent("");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001883 statement("adj[2][0] = spvDet2x2(m[1][0], m[1][1], m[2][0], m[2][1]);");
1884 statement("adj[2][1] = -spvDet2x2(m[0][0], m[0][1], m[2][0], m[2][1]);");
1885 statement("adj[2][2] = spvDet2x2(m[0][0], m[0][1], m[1][0], m[1][1]);");
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001886 statement_no_indent("");
1887 statement("// Calculate the determinant as a combination of the cofactors of the first row.");
1888 statement("float det = (adj[0][0] * m[0][0]) + (adj[0][1] * m[1][0]) + (adj[0][2] * m[2][0]);");
1889 statement_no_indent("");
1890 statement("// Divide the classical adjoint matrix by the determinant.");
1891 statement("// If determinant is zero, matrix is not invertable, so leave it unchanged.");
1892 statement("return (det != 0.0f) ? (adj * (1.0f / det)) : m;");
1893 end_scope();
1894 statement("");
1895 }
1896
1897 if (requires_inverse_4x4)
1898 {
1899 if (!requires_inverse_3x3)
1900 {
1901 statement("// Returns the determinant of a 2x2 matrix.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001902 statement("float spvDet2x2(float a1, float a2, float b1, float b2)");
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001903 begin_scope();
1904 statement("return a1 * b2 - b1 * a2;");
1905 end_scope();
1906 statement("");
1907 }
1908
1909 statement("// Returns the determinant of a 3x3 matrix.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001910 statement("float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001911 "float c2, float c3)");
1912 begin_scope();
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001913 statement("return a1 * spvDet2x2(b2, b3, c2, c3) - b1 * spvDet2x2(a2, a3, c2, c3) + c1 * "
1914 "spvDet2x2(a2, a3, "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001915 "b2, b3);");
1916 end_scope();
1917 statement_no_indent("");
1918 statement("// Returns the inverse of a matrix, by using the algorithm of calculating the classical");
1919 statement("// adjoint and dividing by the determinant. The contents of the matrix are changed.");
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001920 statement("float4x4 spvInverse(float4x4 m)");
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001921 begin_scope();
1922 statement("float4x4 adj; // The adjoint matrix (inverse after dividing by determinant)");
1923 statement_no_indent("");
1924 statement("// Create the transpose of the cofactors, as the classical adjoint of the matrix.");
1925 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001926 "adj[0][0] = spvDet3x3(m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001927 "m[3][3]);");
1928 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001929 "adj[0][1] = -spvDet3x3(m[0][1], m[0][2], m[0][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001930 "m[3][3]);");
1931 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001932 "adj[0][2] = spvDet3x3(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[3][1], m[3][2], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001933 "m[3][3]);");
1934 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001935 "adj[0][3] = -spvDet3x3(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001936 "m[2][3]);");
1937 statement_no_indent("");
1938 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001939 "adj[1][0] = -spvDet3x3(m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001940 "m[3][3]);");
1941 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001942 "adj[1][1] = spvDet3x3(m[0][0], m[0][2], m[0][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001943 "m[3][3]);");
1944 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001945 "adj[1][2] = -spvDet3x3(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[3][0], m[3][2], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001946 "m[3][3]);");
1947 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001948 "adj[1][3] = spvDet3x3(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001949 "m[2][3]);");
1950 statement_no_indent("");
1951 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001952 "adj[2][0] = spvDet3x3(m[1][0], m[1][1], m[1][3], m[2][0], m[2][1], m[2][3], m[3][0], m[3][1], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001953 "m[3][3]);");
1954 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001955 "adj[2][1] = -spvDet3x3(m[0][0], m[0][1], m[0][3], m[2][0], m[2][1], m[2][3], m[3][0], m[3][1], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001956 "m[3][3]);");
1957 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001958 "adj[2][2] = spvDet3x3(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[3][0], m[3][1], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001959 "m[3][3]);");
1960 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001961 "adj[2][3] = -spvDet3x3(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[2][0], m[2][1], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001962 "m[2][3]);");
1963 statement_no_indent("");
1964 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001965 "adj[3][0] = -spvDet3x3(m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001966 "m[3][2]);");
1967 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001968 "adj[3][1] = spvDet3x3(m[0][0], m[0][1], m[0][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001969 "m[3][2]);");
1970 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001971 "adj[3][2] = -spvDet3x3(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[3][0], m[3][1], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001972 "m[3][2]);");
1973 statement(
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001974 "adj[3][3] = spvDet3x3(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], "
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01001975 "m[2][2]);");
1976 statement_no_indent("");
1977 statement("// Calculate the determinant as a combination of the cofactors of the first row.");
1978 statement("float det = (adj[0][0] * m[0][0]) + (adj[0][1] * m[1][0]) + (adj[0][2] * m[2][0]) + (adj[0][3] "
1979 "* m[3][0]);");
1980 statement_no_indent("");
1981 statement("// Divide the classical adjoint matrix by the determinant.");
1982 statement("// If determinant is zero, matrix is not invertable, so leave it unchanged.");
1983 statement("return (det != 0.0f) ? (adj * (1.0f / det)) : m;");
1984 end_scope();
1985 statement("");
1986 }
Hans-Kristian Arntzen041f1032019-07-03 12:24:58 +02001987
1988 if (requires_scalar_reflect)
1989 {
1990 // FP16/FP64? No templates in HLSL.
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01001991 statement("float spvReflect(float i, float n)");
Hans-Kristian Arntzen041f1032019-07-03 12:24:58 +02001992 begin_scope();
1993 statement("return i - 2.0 * dot(n, i) * n;");
1994 end_scope();
1995 statement("");
1996 }
1997
1998 if (requires_scalar_refract)
1999 {
2000 // FP16/FP64? No templates in HLSL.
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01002001 statement("float spvRefract(float i, float n, float eta)");
Hans-Kristian Arntzen041f1032019-07-03 12:24:58 +02002002 begin_scope();
Hans-Kristian Arntzen4056d0b2019-07-03 14:32:06 +02002003 statement("float NoI = n * i;");
2004 statement("float NoI2 = NoI * NoI;");
2005 statement("float k = 1.0 - eta * eta * (1.0 - NoI2);");
Hans-Kristian Arntzen041f1032019-07-03 12:24:58 +02002006 statement("if (k < 0.0)");
2007 begin_scope();
2008 statement("return 0.0;");
2009 end_scope();
2010 statement("else");
2011 begin_scope();
Hans-Kristian Arntzen4056d0b2019-07-03 14:32:06 +02002012 statement("return eta * i - (eta * NoI + sqrt(k)) * n;");
Hans-Kristian Arntzen041f1032019-07-03 12:24:58 +02002013 end_scope();
2014 end_scope();
2015 statement("");
2016 }
Hans-Kristian Arntzenc7eda1b2019-07-17 11:24:31 +02002017
2018 if (requires_scalar_faceforward)
2019 {
2020 // FP16/FP64? No templates in HLSL.
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01002021 statement("float spvFaceForward(float n, float i, float nref)");
Hans-Kristian Arntzenc7eda1b2019-07-17 11:24:31 +02002022 begin_scope();
2023 statement("return i * nref < 0.0 ? n : -n;");
2024 end_scope();
2025 statement("");
2026 }
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02002027
2028 for (TypeID type_id : composite_selection_workaround_types)
2029 {
2030 // Need out variable since HLSL does not support returning arrays.
2031 auto &type = get<SPIRType>(type_id);
2032 auto type_str = type_to_glsl(type);
2033 auto type_arr_str = type_to_array_glsl(type);
2034 statement("void spvSelectComposite(out ", type_str, " out_value", type_arr_str, ", bool cond, ",
2035 type_str, " true_val", type_arr_str, ", ",
2036 type_str, " false_val", type_arr_str, ")");
2037 begin_scope();
2038 statement("if (cond)");
2039 begin_scope();
2040 statement("out_value = true_val;");
2041 end_scope();
2042 statement("else");
2043 begin_scope();
2044 statement("out_value = false_val;");
2045 end_scope();
2046 end_scope();
2047 statement("");
2048 }
Robert Konrad02fd8e92016-08-14 17:58:56 +02002049}
2050
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02002051void CompilerHLSL::emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav,
2052 const char *type_qualifier)
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02002053{
2054 if (variant_mask == 0)
2055 return;
2056
2057 static const char *types[QueryTypeCount] = { "float", "int", "uint" };
2058 static const char *dims[QueryDimCount] = { "Texture1D", "Texture1DArray", "Texture2D", "Texture2DArray",
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02002059 "Texture3D", "Buffer", "TextureCube", "TextureCubeArray",
2060 "Texture2DMS", "Texture2DMSArray" };
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02002061
2062 static const bool has_lod[QueryDimCount] = { true, true, true, true, true, false, true, true, false, false };
2063
2064 static const char *ret_types[QueryDimCount] = {
2065 "uint", "uint2", "uint2", "uint3", "uint3", "uint", "uint2", "uint3", "uint2", "uint3",
2066 };
2067
2068 static const uint32_t return_arguments[QueryDimCount] = {
2069 1, 2, 2, 3, 3, 1, 2, 3, 2, 3,
2070 };
2071
2072 for (uint32_t index = 0; index < QueryDimCount; index++)
2073 {
2074 for (uint32_t type_index = 0; type_index < QueryTypeCount; type_index++)
2075 {
2076 uint32_t bit = 16 * type_index + index;
2077 uint64_t mask = 1ull << bit;
2078
2079 if ((variant_mask & mask) == 0)
2080 continue;
2081
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01002082 statement(ret_types[index], " spv", (uav ? "Image" : "Texture"), "Size(", (uav ? "RW" : ""),
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02002083 dims[index], "<", type_qualifier, types[type_index], vecsize_qualifier, "> Tex, ",
2084 (uav ? "" : "uint Level, "), "out uint Param)");
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02002085 begin_scope();
2086 statement(ret_types[index], " ret;");
2087 switch (return_arguments[index])
2088 {
2089 case 1:
2090 if (has_lod[index] && !uav)
2091 statement("Tex.GetDimensions(Level, ret.x, Param);");
2092 else
2093 {
2094 statement("Tex.GetDimensions(ret.x);");
2095 statement("Param = 0u;");
2096 }
2097 break;
2098 case 2:
2099 if (has_lod[index] && !uav)
2100 statement("Tex.GetDimensions(Level, ret.x, ret.y, Param);");
2101 else if (!uav)
2102 statement("Tex.GetDimensions(ret.x, ret.y, Param);");
2103 else
2104 {
2105 statement("Tex.GetDimensions(ret.x, ret.y);");
2106 statement("Param = 0u;");
2107 }
2108 break;
2109 case 3:
2110 if (has_lod[index] && !uav)
2111 statement("Tex.GetDimensions(Level, ret.x, ret.y, ret.z, Param);");
2112 else if (!uav)
2113 statement("Tex.GetDimensions(ret.x, ret.y, ret.z, Param);");
2114 else
2115 {
2116 statement("Tex.GetDimensions(ret.x, ret.y, ret.z);");
2117 statement("Param = 0u;");
2118 }
2119 break;
2120 }
2121
2122 statement("return ret;");
2123 end_scope();
2124 statement("");
2125 }
2126 }
2127}
2128
Hans-Kristian Arntzen620d01c2017-10-10 16:11:25 +02002129string CompilerHLSL::layout_for_member(const SPIRType &type, uint32_t index)
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002130{
Hans-Kristian Arntzenf1e85552018-06-05 09:42:07 +02002131 auto &flags = get_member_decoration_bitset(type.self, index);
Hans-Kristian Arntzen620d01c2017-10-10 16:11:25 +02002132
Hans-Kristian Arntzenf1e85552018-06-05 09:42:07 +02002133 // HLSL can emit row_major or column_major decoration in any struct.
2134 // Do not try to merge combined decorations for children like in GLSL.
Hans-Kristian Arntzen620d01c2017-10-10 16:11:25 +02002135
2136 // Flip the convention. HLSL is a bit odd in that the memory layout is column major ... but the language API is "row-major".
2137 // The way to deal with this is to multiply everything in inverse order, and reverse the memory layout.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002138 if (flags.get(DecorationColMajor))
Hans-Kristian Arntzen620d01c2017-10-10 16:11:25 +02002139 return "row_major ";
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002140 else if (flags.get(DecorationRowMajor))
Hans-Kristian Arntzen620d01c2017-10-10 16:11:25 +02002141 return "column_major ";
2142
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002143 return "";
2144}
2145
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +02002146void CompilerHLSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
msiglreithd096f5c2017-11-27 16:00:56 +01002147 const string &qualifier, uint32_t base_offset)
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +02002148{
2149 auto &membertype = get<SPIRType>(member_type_id);
2150
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002151 Bitset memberflags;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002152 auto &memb = ir.meta[type.self].members;
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +02002153 if (index < memb.size())
2154 memberflags = memb[index].decoration_flags;
2155
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +02002156 string packing_offset;
msiglreithd096f5c2017-11-27 16:00:56 +01002157 bool is_push_constant = type.storage == StorageClassPushConstant;
2158
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002159 if ((has_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset) || is_push_constant) &&
msiglreithd096f5c2017-11-27 16:00:56 +01002160 has_member_decoration(type.self, index, DecorationOffset))
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +02002161 {
msiglreithd096f5c2017-11-27 16:00:56 +01002162 uint32_t offset = memb[index].offset - base_offset;
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +02002163 if (offset & 3)
2164 SPIRV_CROSS_THROW("Cannot pack on tighter bounds than 4 bytes in HLSL.");
2165
2166 static const char *packing_swizzle[] = { "", ".y", ".z", ".w" };
2167 packing_offset = join(" : packoffset(c", offset / 16, packing_swizzle[(offset & 15) >> 2], ")");
2168 }
2169
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002170 statement(layout_for_member(type, index), qualifier,
Hans-Kristian Arntzenf0200bb2017-10-10 13:15:49 +02002171 variable_decl(membertype, to_member_name(type, index)), packing_offset, ";");
2172}
2173
Konstantin Pail251361b2022-03-15 21:54:29 +03002174void CompilerHLSL::emit_rayquery_function(const char *commited, const char *candidate, const uint32_t *ops)
2175{
2176 flush_variable_declaration(ops[0]);
2177 uint32_t is_commited = evaluate_constant_u32(ops[3]);
2178 emit_op(ops[0], ops[1], join(to_expression(ops[2]), is_commited ? commited : candidate), false);
2179}
2180
Robert Konrad99469f02017-01-24 09:17:43 +01002181void CompilerHLSL::emit_buffer_block(const SPIRVariable &var)
2182{
2183 auto &type = get<SPIRType>(var.basetype);
2184
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02002185 bool is_uav = var.storage == StorageClassStorageBuffer || has_decoration(type.self, DecorationBufferBlock);
Hans-Kristian Arntzenecf56cf2017-06-30 10:34:21 +02002186
Shintaro Sakaharaed4ded02022-02-16 21:53:24 +09002187 if (flattened_buffer_blocks.count(var.self))
2188 {
2189 emit_buffer_block_flattened(var);
2190 }
2191 else if (is_uav)
Robert Konrad99469f02017-01-24 09:17:43 +01002192 {
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002193 Bitset flags = ir.get_buffer_block_flags(var);
Bryan Bernhart17bccc92020-05-27 13:08:15 -07002194 bool is_readonly = flags.get(DecorationNonWritable) && !is_hlsl_force_storage_buffer_as_uav(var.self);
Hans-Kristian Arntzen185551b2020-03-05 10:37:36 +01002195 bool is_coherent = flags.get(DecorationCoherent) && !is_readonly;
Chip Davis2eff4202019-08-04 00:07:20 -05002196 bool is_interlocked = interlocked_resources.count(var.self) > 0;
2197 const char *type_name = "ByteAddressBuffer ";
2198 if (!is_readonly)
2199 type_name = is_interlocked ? "RasterizerOrderedByteAddressBuffer " : "RWByteAddressBuffer ";
Hans-Kristian Arntzen247ab1c2017-08-10 17:22:32 +02002200 add_resource_name(var.self);
Chip Davis2eff4202019-08-04 00:07:20 -05002201 statement(is_coherent ? "globallycoherent " : "", type_name, to_name(var.self), type_to_array_glsl(type),
2202 to_resource_binding(var), ";");
Hans-Kristian Arntzenecf56cf2017-06-30 10:34:21 +02002203 }
2204 else
2205 {
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002206 if (type.array.empty())
Hans-Kristian Arntzen247ab1c2017-08-10 17:22:32 +02002207 {
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002208 // Flatten the top-level struct so we can use packoffset,
2209 // this restriction is similar to GLSL where layout(offset) is not possible on sub-structs.
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002210 flattened_structs[var.self] = false;
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002211
Hans-Kristian Arntzen226d8372018-10-22 09:50:04 +02002212 // Prefer the block name if possible.
2213 auto buffer_name = to_name(type.self, false);
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002214 if (ir.meta[type.self].decoration.alias.empty() ||
2215 resource_names.find(buffer_name) != end(resource_names) ||
2216 block_names.find(buffer_name) != end(block_names))
2217 {
Hans-Kristian Arntzen226d8372018-10-22 09:50:04 +02002218 buffer_name = get_block_fallback_name(var.self);
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002219 }
2220
2221 add_variable(block_names, resource_names, buffer_name);
Hans-Kristian Arntzen226d8372018-10-22 09:50:04 +02002222
2223 // If for some reason buffer_name is an illegal name, make a final fallback to a workaround name.
2224 // This cannot conflict with anything else, so we're safe now.
2225 if (buffer_name.empty())
2226 buffer_name = join("_", get<SPIRType>(var.basetype).self, "_", var.self);
2227
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01002228 uint32_t failed_index = 0;
2229 if (buffer_is_packing_standard(type, BufferPackingHLSLCbufferPackOffset, &failed_index))
Hans-Kristian Arntzene73d9be2019-11-06 11:04:52 +01002230 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
2231 else
2232 {
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01002233 SPIRV_CROSS_THROW(join("cbuffer ID ", var.self, " (name: ", buffer_name, "), member index ",
2234 failed_index, " (name: ", to_member_name(type, failed_index),
Hans-Kristian Arntzene73d9be2019-11-06 11:04:52 +01002235 ") cannot be expressed with either HLSL packing layout or packoffset."));
2236 }
2237
Hans-Kristian Arntzen9728f9c2019-01-04 12:15:43 +01002238 block_names.insert(buffer_name);
Hans-Kristian Arntzen226d8372018-10-22 09:50:04 +02002239
2240 // Save for post-reflection later.
2241 declared_block_names[var.self] = buffer_name;
2242
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002243 type.member_name_cache.clear();
Hans-Kristian Arntzend7090b82019-02-13 16:39:59 +01002244 // var.self can be used as a backup name for the block name,
2245 // so we need to make sure we don't disturb the name here on a recompile.
2246 // It will need to be reset if we have to recompile.
2247 preserve_alias_on_reset(var.self);
Hans-Kristian Arntzen94ff3552017-10-10 17:32:26 +02002248 add_resource_name(var.self);
Hans-Kristian Arntzen226d8372018-10-22 09:50:04 +02002249 statement("cbuffer ", buffer_name, to_resource_binding(var));
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002250 begin_scope();
2251
2252 uint32_t i = 0;
2253 for (auto &member : type.member_types)
2254 {
2255 add_member_name(type, i);
Hans-Kristian Arntzen94ff3552017-10-10 17:32:26 +02002256 auto backup_name = get_member_name(type.self, i);
2257 auto member_name = to_member_name(type, i);
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02002258 member_name = join(to_name(var.self), "_", member_name);
2259 ParsedIR::sanitize_underscores(member_name);
2260 set_member_name(type.self, i, member_name);
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002261 emit_struct_member(type, member, i, "");
Hans-Kristian Arntzen94ff3552017-10-10 17:32:26 +02002262 set_member_name(type.self, i, backup_name);
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002263 i++;
2264 }
2265
2266 end_scope_decl();
Hans-Kristian Arntzen226d8372018-10-22 09:50:04 +02002267 statement("");
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002268 }
2269 else
2270 {
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01002271 if (hlsl_options.shader_model < 51)
Hans-Kristian Arntzen74642322017-10-10 16:13:03 +02002272 SPIRV_CROSS_THROW(
2273 "Need ConstantBuffer<T> to use arrays of UBOs, but this is only supported in SM 5.1.");
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002274
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002275 add_resource_name(type.self);
2276 add_resource_name(var.self);
2277
Hans-Kristian Arntzene73d9be2019-11-06 11:04:52 +01002278 // ConstantBuffer<T> does not support packoffset, so it is unuseable unless everything aligns as we expect.
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01002279 uint32_t failed_index = 0;
2280 if (!buffer_is_packing_standard(type, BufferPackingHLSLCbuffer, &failed_index))
Hans-Kristian Arntzene73d9be2019-11-06 11:04:52 +01002281 {
2282 SPIRV_CROSS_THROW(join("HLSL ConstantBuffer<T> ID ", var.self, " (name: ", to_name(type.self),
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01002283 "), member index ", failed_index, " (name: ", to_member_name(type, failed_index),
Hans-Kristian Arntzene73d9be2019-11-06 11:04:52 +01002284 ") cannot be expressed with normal HLSL packing rules."));
2285 }
2286
Hans-Kristian Arntzen6feff982017-10-10 15:37:53 +02002287 emit_struct(get<SPIRType>(type.self));
2288 statement("ConstantBuffer<", to_name(type.self), "> ", to_name(var.self), type_to_array_glsl(type),
2289 to_resource_binding(var), ";");
2290 }
Hans-Kristian Arntzenecf56cf2017-06-30 10:34:21 +02002291 }
Robert Konrad99469f02017-01-24 09:17:43 +01002292}
2293
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02002294void CompilerHLSL::emit_push_constant_block(const SPIRVariable &var)
Robert Konrad99469f02017-01-24 09:17:43 +01002295{
Shintaro Sakaharaed4ded02022-02-16 21:53:24 +09002296 if (flattened_buffer_blocks.count(var.self))
2297 {
2298 emit_buffer_block_flattened(var);
2299 }
2300 else if (root_constants_layout.empty())
msiglreithd096f5c2017-11-27 16:00:56 +01002301 {
2302 emit_buffer_block(var);
2303 }
2304 else
2305 {
2306 for (const auto &layout : root_constants_layout)
2307 {
2308 auto &type = get<SPIRType>(var.basetype);
2309
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01002310 uint32_t failed_index = 0;
2311 if (buffer_is_packing_standard(type, BufferPackingHLSLCbufferPackOffset, &failed_index, layout.start,
2312 layout.end))
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02002313 set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset);
msiglreithd096f5c2017-11-27 16:00:56 +01002314 else
Hans-Kristian Arntzen0b417b52019-11-06 11:20:57 +01002315 {
2316 SPIRV_CROSS_THROW(join("Root constant cbuffer ID ", var.self, " (name: ", to_name(type.self), ")",
2317 ", member index ", failed_index, " (name: ", to_member_name(type, failed_index),
2318 ") cannot be expressed with either HLSL packing layout or packoffset."));
2319 }
msiglreithd096f5c2017-11-27 16:00:56 +01002320
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02002321 flattened_structs[var.self] = false;
msiglreithd096f5c2017-11-27 16:00:56 +01002322 type.member_name_cache.clear();
2323 add_resource_name(var.self);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002324 auto &memb = ir.meta[type.self].members;
msiglreithd096f5c2017-11-27 16:00:56 +01002325
2326 statement("cbuffer SPIRV_CROSS_RootConstant_", to_name(var.self),
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01002327 to_resource_register(HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT, 'b', layout.binding, layout.space));
msiglreithd096f5c2017-11-27 16:00:56 +01002328 begin_scope();
2329
2330 // Index of the next field in the generated root constant constant buffer
2331 auto constant_index = 0u;
2332
2333 // Iterate over all member of the push constant and check which of the fields
2334 // fit into the given root constant layout.
2335 for (auto i = 0u; i < memb.size(); i++)
2336 {
2337 const auto offset = memb[i].offset;
2338 if (layout.start <= offset && offset < layout.end)
2339 {
2340 const auto &member = type.member_types[i];
2341
2342 add_member_name(type, constant_index);
2343 auto backup_name = get_member_name(type.self, i);
2344 auto member_name = to_member_name(type, i);
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02002345 member_name = join(to_name(var.self), "_", member_name);
2346 ParsedIR::sanitize_underscores(member_name);
2347 set_member_name(type.self, constant_index, member_name);
msiglreithd096f5c2017-11-27 16:00:56 +01002348 emit_struct_member(type, member, i, "", layout.start);
2349 set_member_name(type.self, constant_index, backup_name);
2350
2351 constant_index++;
2352 }
2353 }
2354
2355 end_scope_decl();
2356 }
2357 }
Robert Konrad99469f02017-01-24 09:17:43 +01002358}
2359
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002360string CompilerHLSL::to_sampler_expression(uint32_t id)
2361{
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02002362 auto expr = join("_", to_non_uniform_aware_expression(id));
Hans-Kristian Arntzenec1180f2018-01-04 12:14:18 +01002363 auto index = expr.find_first_of('[');
2364 if (index == string::npos)
2365 {
2366 return expr + "_sampler";
2367 }
2368 else
2369 {
2370 // We have an expression like _ident[array], so we cannot tack on _sampler, insert it inside the string instead.
2371 return expr.insert(index, "_sampler");
2372 }
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002373}
2374
Hans-Kristian Arntzen947f7012017-05-07 13:28:08 +02002375void CompilerHLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
2376{
Minmin Gonge3ebfda2018-11-10 13:33:15 -08002377 if (hlsl_options.shader_model >= 40 && combined_image_samplers.empty())
2378 {
2379 set<SPIRCombinedImageSampler>(result_id, result_type, image_id, samp_id);
2380 }
2381 else
2382 {
2383 // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types.
2384 emit_op(result_type, result_id, to_combined_image_sampler(image_id, samp_id), true, true);
2385 }
Hans-Kristian Arntzen947f7012017-05-07 13:28:08 +02002386}
2387
Chip Davis39dce882019-08-02 15:11:19 -05002388string CompilerHLSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id)
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002389{
Chip Davis39dce882019-08-02 15:11:19 -05002390 string arg_str = CompilerGLSL::to_func_call_arg(arg, id);
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002391
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01002392 if (hlsl_options.shader_model <= 30)
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002393 return arg_str;
2394
2395 // Manufacture automatic sampler arg if the arg is a SampledImage texture and we're in modern HLSL.
Hans-Kristian Arntzenec1180f2018-01-04 12:14:18 +01002396 auto &type = expression_type(id);
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002397
Hans-Kristian Arntzenec1180f2018-01-04 12:14:18 +01002398 // We don't have to consider combined image samplers here via OpSampledImage because
2399 // those variables cannot be passed as arguments to functions.
2400 // Only global SampledImage variables may be used as arguments.
2401 if (type.basetype == SPIRType::SampledImage && type.image.dim != DimBuffer)
2402 arg_str += ", " + to_sampler_expression(id);
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002403
2404 return arg_str;
2405}
2406
Hans-Kristian Arntzen06ca9ac2022-07-22 12:04:33 +02002407string CompilerHLSL::get_inner_entry_point_name() const
2408{
2409 auto &execution = get_entry_point();
2410
2411 if (hlsl_options.use_entry_point_name)
2412 {
2413 auto name = join(execution.name, "_inner");
2414 ParsedIR::sanitize_underscores(name);
2415 return name;
2416 }
2417
2418 if (execution.model == ExecutionModelVertex)
2419 return "vert_main";
2420 else if (execution.model == ExecutionModelFragment)
2421 return "frag_main";
2422 else if (execution.model == ExecutionModelGLCompute)
2423 return "comp_main";
2424 else
2425 SPIRV_CROSS_THROW("Unsupported execution model.");
2426}
2427
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002428void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &return_flags)
Robert Konrad80fcf552016-08-14 21:33:32 +02002429{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002430 if (func.self != ir.default_entry_point)
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +01002431 add_function_overload(func);
2432
Robert Konrad80fcf552016-08-14 21:33:32 +02002433 // Avoid shadow declarations.
2434 local_variable_names = resource_names;
2435
2436 string decl;
2437
2438 auto &type = get<SPIRType>(func.return_type);
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01002439 if (type.array.empty())
2440 {
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +02002441 decl += flags_to_qualifiers_glsl(type, return_flags);
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01002442 decl += type_to_glsl(type);
2443 decl += " ";
2444 }
2445 else
2446 {
2447 // We cannot return arrays in HLSL, so "return" through an out variable.
2448 decl = "void ";
2449 }
Robert Konrad80fcf552016-08-14 21:33:32 +02002450
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002451 if (func.self == ir.default_entry_point)
Robert Konrad80fcf552016-08-14 21:33:32 +02002452 {
Hans-Kristian Arntzen06ca9ac2022-07-22 12:04:33 +02002453 decl += get_inner_entry_point_name();
Robert Konrad80fcf552016-08-14 21:33:32 +02002454 processing_entry_point = true;
2455 }
2456 else
2457 decl += to_name(func.self);
2458
2459 decl += "(";
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02002460 SmallVector<string> arglist;
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01002461
2462 if (!type.array.empty())
2463 {
2464 // Fake array returns by writing to an out array instead.
Hans-Kristian Arntzenb778e162018-11-12 09:58:27 +01002465 string out_argument;
2466 out_argument += "out ";
2467 out_argument += type_to_glsl(type);
2468 out_argument += " ";
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01002469 out_argument += "spvReturnValue";
Hans-Kristian Arntzenb778e162018-11-12 09:58:27 +01002470 out_argument += type_to_array_glsl(type);
Daniel Thornburgh44c33332022-03-02 23:02:38 +00002471 arglist.push_back(std::move(out_argument));
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01002472 }
2473
Robert Konrad80fcf552016-08-14 21:33:32 +02002474 for (auto &arg : func.arguments)
2475 {
Hans-Kristian Arntzenb778e162018-11-12 09:58:27 +01002476 // Do not pass in separate images or samplers if we're remapping
2477 // to combined image samplers.
2478 if (skip_argument(arg.id))
2479 continue;
2480
Robert Konrad80fcf552016-08-14 21:33:32 +02002481 // Might change the variable name if it already exists in this function.
2482 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
2483 // to use same name for variables.
2484 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
2485 add_local_variable_name(arg.id);
2486
Hans-Kristian Arntzenb778e162018-11-12 09:58:27 +01002487 arglist.push_back(argument_decl(arg));
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002488
2489 // Flatten a combined sampler to two separate arguments in modern HLSL.
2490 auto &arg_type = get<SPIRType>(arg.type);
Hans-Kristian Arntzen9a527132018-03-09 15:26:36 +01002491 if (hlsl_options.shader_model > 30 && arg_type.basetype == SPIRType::SampledImage &&
2492 arg_type.image.dim != DimBuffer)
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002493 {
2494 // Manufacture automatic sampler arg for SampledImage texture
Bill Hollingsfd252b22021-11-08 15:59:45 -05002495 arglist.push_back(join(is_depth_image(arg_type, arg.id) ? "SamplerComparisonState " : "SamplerState ",
Hans-Kristian Arntzenb778e162018-11-12 09:58:27 +01002496 to_sampler_expression(arg.id), type_to_array_glsl(arg_type)));
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02002497 }
2498
Robert Konrad80fcf552016-08-14 21:33:32 +02002499 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
2500 auto *var = maybe_get<SPIRVariable>(arg.id);
2501 if (var)
2502 var->parameter = &arg;
2503 }
2504
Hans-Kristian Arntzenb778e162018-11-12 09:58:27 +01002505 for (auto &arg : func.shadow_arguments)
2506 {
2507 // Might change the variable name if it already exists in this function.
2508 // SPIRV OpName doesn't have any semantic effect, so it's valid for an implementation
2509 // to use same name for variables.
2510 // Since we want to make the GLSL debuggable and somewhat sane, use fallback names for variables which are duplicates.
2511 add_local_variable_name(arg.id);
2512
2513 arglist.push_back(argument_decl(arg));
2514
2515 // Hold a pointer to the parameter so we can invalidate the readonly field if needed.
2516 auto *var = maybe_get<SPIRVariable>(arg.id);
2517 if (var)
2518 var->parameter = &arg;
2519 }
2520
2521 decl += merge(arglist);
Robert Konrad80fcf552016-08-14 21:33:32 +02002522 decl += ")";
2523 statement(decl);
2524}
2525
2526void CompilerHLSL::emit_hlsl_entry_point()
2527{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02002528 SmallVector<string> arguments;
Robert Konrad80fcf552016-08-14 21:33:32 +02002529
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01002530 if (require_input)
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002531 arguments.push_back("SPIRV_Cross_Input stage_input");
2532
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002533 auto &execution = get_entry_point();
Hans-Kristian Arntzene2bb5b82017-08-15 09:34:30 +02002534
msiglreithf4bde2b2017-11-21 14:51:03 +01002535 switch (execution.model)
2536 {
2537 case ExecutionModelGLCompute:
Hans-Kristian Arntzene2bb5b82017-08-15 09:34:30 +02002538 {
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002539 SpecializationConstant wg_x, wg_y, wg_z;
2540 get_work_group_size_specialization_constants(wg_x, wg_y, wg_z);
2541
2542 uint32_t x = execution.workgroup_size.x;
2543 uint32_t y = execution.workgroup_size.y;
2544 uint32_t z = execution.workgroup_size.z;
2545
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +01002546 if (!execution.workgroup_size.constant && execution.flags.get(ExecutionModeLocalSizeId))
2547 {
2548 if (execution.workgroup_size.id_x)
2549 x = get<SPIRConstant>(execution.workgroup_size.id_x).scalar();
2550 if (execution.workgroup_size.id_y)
2551 y = get<SPIRConstant>(execution.workgroup_size.id_y).scalar();
2552 if (execution.workgroup_size.id_z)
2553 z = get<SPIRConstant>(execution.workgroup_size.id_z).scalar();
2554 }
2555
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002556 auto x_expr = wg_x.id ? get<SPIRConstant>(wg_x.id).specialization_constant_macro_name : to_string(x);
2557 auto y_expr = wg_y.id ? get<SPIRConstant>(wg_y.id).specialization_constant_macro_name : to_string(y);
2558 auto z_expr = wg_z.id ? get<SPIRConstant>(wg_z.id).specialization_constant_macro_name : to_string(z);
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002559
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01002560 statement("[numthreads(", x_expr, ", ", y_expr, ", ", z_expr, ")]");
msiglreithf4bde2b2017-11-21 14:51:03 +01002561 break;
2562 }
2563 case ExecutionModelFragment:
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002564 if (execution.flags.get(ExecutionModeEarlyFragmentTests))
msiglreithf4bde2b2017-11-21 14:51:03 +01002565 statement("[earlydepthstencil]");
2566 break;
2567 default:
2568 break;
Hans-Kristian Arntzene2bb5b82017-08-15 09:34:30 +02002569 }
2570
Hans-Kristian Arntzen06ca9ac2022-07-22 12:04:33 +02002571 const char *entry_point_name;
2572 if (hlsl_options.use_entry_point_name)
2573 entry_point_name = get_entry_point().name.c_str();
2574 else
2575 entry_point_name = "main";
2576
2577 statement(require_output ? "SPIRV_Cross_Output " : "void ", entry_point_name, "(", merge(arguments), ")");
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002578 begin_scope();
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01002579 bool legacy = hlsl_options.shader_model <= 30;
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002580
2581 // Copy builtins from entry point arguments to globals.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002582 active_input_builtins.for_each_bit([&](uint32_t i) {
Hans-Kristian Arntzenc8d60912017-07-24 10:07:02 +02002583 auto builtin = builtin_to_glsl(static_cast<BuiltIn>(i), StorageClassInput);
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002584 switch (static_cast<BuiltIn>(i))
2585 {
2586 case BuiltInFragCoord:
2587 // VPOS in D3D9 is sampled at integer locations, apply half-pixel offset to be consistent.
2588 // TODO: Do we need an option here? Any reason why a D3D9 shader would be used
2589 // on a D3D10+ system with a different rasterization config?
2590 if (legacy)
2591 statement(builtin, " = stage_input.", builtin, " + float4(0.5f, 0.5f, 0.0f, 0.0f);");
2592 else
Hans-Kristian Arntzenfdbc80d2020-08-20 16:22:48 +02002593 {
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002594 statement(builtin, " = stage_input.", builtin, ";");
Hans-Kristian Arntzenfdbc80d2020-08-20 16:22:48 +02002595 // ZW are undefined in D3D9, only do this fixup here.
2596 statement(builtin, ".w = 1.0 / ", builtin, ".w;");
2597 }
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002598 break;
2599
Hans-Kristian Arntzen5e9b53e2017-12-06 11:01:32 +01002600 case BuiltInVertexId:
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002601 case BuiltInVertexIndex:
2602 case BuiltInInstanceIndex:
2603 // D3D semantics are uint, but shader wants int.
Hans-Kristian Arntzena2a44d92019-01-11 10:32:14 +01002604 if (hlsl_options.support_nonzero_base_vertex_base_instance)
2605 {
2606 if (static_cast<BuiltIn>(i) == BuiltInInstanceIndex)
2607 statement(builtin, " = int(stage_input.", builtin, ") + SPIRV_Cross_BaseInstance;");
2608 else
2609 statement(builtin, " = int(stage_input.", builtin, ") + SPIRV_Cross_BaseVertex;");
2610 }
2611 else
2612 statement(builtin, " = int(stage_input.", builtin, ");");
2613 break;
2614
2615 case BuiltInInstanceId:
2616 // D3D semantics are uint, but shader wants int.
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002617 statement(builtin, " = int(stage_input.", builtin, ");");
2618 break;
2619
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01002620 case BuiltInNumWorkgroups:
Hans-Kristian Arntzenf6d08e62018-02-23 15:56:25 +01002621 case BuiltInPointCoord:
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02002622 case BuiltInSubgroupSize:
2623 case BuiltInSubgroupLocalInvocationId:
Pedro J. Estébanez278a4c82022-03-04 09:09:08 +01002624 case BuiltInHelperInvocation:
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02002625 break;
2626
2627 case BuiltInSubgroupEqMask:
2628 // Emulate these ...
2629 // No 64-bit in HLSL, so have to do it in 32-bit and unroll.
2630 statement("gl_SubgroupEqMask = 1u << (WaveGetLaneIndex() - uint4(0, 32, 64, 96));");
2631 statement("if (WaveGetLaneIndex() >= 32) gl_SubgroupEqMask.x = 0;");
2632 statement("if (WaveGetLaneIndex() >= 64 || WaveGetLaneIndex() < 32) gl_SubgroupEqMask.y = 0;");
2633 statement("if (WaveGetLaneIndex() >= 96 || WaveGetLaneIndex() < 64) gl_SubgroupEqMask.z = 0;");
2634 statement("if (WaveGetLaneIndex() < 96) gl_SubgroupEqMask.w = 0;");
2635 break;
2636
2637 case BuiltInSubgroupGeMask:
2638 // Emulate these ...
2639 // No 64-bit in HLSL, so have to do it in 32-bit and unroll.
2640 statement("gl_SubgroupGeMask = ~((1u << (WaveGetLaneIndex() - uint4(0, 32, 64, 96))) - 1u);");
2641 statement("if (WaveGetLaneIndex() >= 32) gl_SubgroupGeMask.x = 0u;");
2642 statement("if (WaveGetLaneIndex() >= 64) gl_SubgroupGeMask.y = 0u;");
2643 statement("if (WaveGetLaneIndex() >= 96) gl_SubgroupGeMask.z = 0u;");
2644 statement("if (WaveGetLaneIndex() < 32) gl_SubgroupGeMask.y = ~0u;");
2645 statement("if (WaveGetLaneIndex() < 64) gl_SubgroupGeMask.z = ~0u;");
2646 statement("if (WaveGetLaneIndex() < 96) gl_SubgroupGeMask.w = ~0u;");
2647 break;
2648
2649 case BuiltInSubgroupGtMask:
2650 // Emulate these ...
2651 // No 64-bit in HLSL, so have to do it in 32-bit and unroll.
2652 statement("uint gt_lane_index = WaveGetLaneIndex() + 1;");
2653 statement("gl_SubgroupGtMask = ~((1u << (gt_lane_index - uint4(0, 32, 64, 96))) - 1u);");
2654 statement("if (gt_lane_index >= 32) gl_SubgroupGtMask.x = 0u;");
2655 statement("if (gt_lane_index >= 64) gl_SubgroupGtMask.y = 0u;");
2656 statement("if (gt_lane_index >= 96) gl_SubgroupGtMask.z = 0u;");
2657 statement("if (gt_lane_index >= 128) gl_SubgroupGtMask.w = 0u;");
2658 statement("if (gt_lane_index < 32) gl_SubgroupGtMask.y = ~0u;");
2659 statement("if (gt_lane_index < 64) gl_SubgroupGtMask.z = ~0u;");
2660 statement("if (gt_lane_index < 96) gl_SubgroupGtMask.w = ~0u;");
2661 break;
2662
2663 case BuiltInSubgroupLeMask:
2664 // Emulate these ...
2665 // No 64-bit in HLSL, so have to do it in 32-bit and unroll.
2666 statement("uint le_lane_index = WaveGetLaneIndex() + 1;");
2667 statement("gl_SubgroupLeMask = (1u << (le_lane_index - uint4(0, 32, 64, 96))) - 1u;");
2668 statement("if (le_lane_index >= 32) gl_SubgroupLeMask.x = ~0u;");
2669 statement("if (le_lane_index >= 64) gl_SubgroupLeMask.y = ~0u;");
2670 statement("if (le_lane_index >= 96) gl_SubgroupLeMask.z = ~0u;");
2671 statement("if (le_lane_index >= 128) gl_SubgroupLeMask.w = ~0u;");
2672 statement("if (le_lane_index < 32) gl_SubgroupLeMask.y = 0u;");
2673 statement("if (le_lane_index < 64) gl_SubgroupLeMask.z = 0u;");
2674 statement("if (le_lane_index < 96) gl_SubgroupLeMask.w = 0u;");
2675 break;
2676
2677 case BuiltInSubgroupLtMask:
2678 // Emulate these ...
2679 // No 64-bit in HLSL, so have to do it in 32-bit and unroll.
2680 statement("gl_SubgroupLtMask = (1u << (WaveGetLaneIndex() - uint4(0, 32, 64, 96))) - 1u;");
2681 statement("if (WaveGetLaneIndex() >= 32) gl_SubgroupLtMask.x = ~0u;");
2682 statement("if (WaveGetLaneIndex() >= 64) gl_SubgroupLtMask.y = ~0u;");
2683 statement("if (WaveGetLaneIndex() >= 96) gl_SubgroupLtMask.z = ~0u;");
2684 statement("if (WaveGetLaneIndex() < 32) gl_SubgroupLtMask.y = 0u;");
2685 statement("if (WaveGetLaneIndex() < 64) gl_SubgroupLtMask.z = 0u;");
2686 statement("if (WaveGetLaneIndex() < 96) gl_SubgroupLtMask.w = 0u;");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01002687 break;
2688
2689 case BuiltInClipDistance:
2690 for (uint32_t clip = 0; clip < clip_distance_count; clip++)
Hans-Kristian Arntzen4543dac2018-02-23 13:13:02 +01002691 statement("gl_ClipDistance[", clip, "] = stage_input.gl_ClipDistance", clip / 4, ".", "xyzw"[clip & 3],
2692 ";");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01002693 break;
2694
2695 case BuiltInCullDistance:
Hans-Kristian Arntzen0673f272018-02-22 17:00:41 +01002696 for (uint32_t cull = 0; cull < cull_distance_count; cull++)
Hans-Kristian Arntzen4543dac2018-02-23 13:13:02 +01002697 statement("gl_CullDistance[", cull, "] = stage_input.gl_CullDistance", cull / 4, ".", "xyzw"[cull & 3],
2698 ";");
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01002699 break;
2700
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002701 default:
2702 statement(builtin, " = stage_input.", builtin, ";");
2703 break;
2704 }
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002705 });
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002706
2707 // Copy from stage input struct to globals.
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002708 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002709 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002710 bool block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002711
2712 if (var.storage != StorageClassInput)
2713 return;
2714
2715 bool need_matrix_unroll = var.storage == StorageClassInput && execution.model == ExecutionModelVertex;
2716
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002717 if (!var.remapped_variable && type.pointer && !is_builtin_variable(var) &&
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002718 interface_variable_exists_in_entry_point(var.self))
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002719 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002720 if (block)
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002721 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002722 auto type_name = to_name(type.self);
2723 auto var_name = to_name(var.self);
2724 for (uint32_t mbr_idx = 0; mbr_idx < uint32_t(type.member_types.size()); mbr_idx++)
2725 {
2726 auto mbr_name = to_member_name(type, mbr_idx);
2727 auto flat_name = join(type_name, "_", mbr_name);
2728 statement(var_name, ".", mbr_name, " = stage_input.", flat_name, ";");
2729 }
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002730 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002731 else
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002732 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002733 auto name = to_name(var.self);
2734 auto &mtype = this->get<SPIRType>(var.basetype);
2735 if (need_matrix_unroll && mtype.columns > 1)
2736 {
2737 // Unroll matrices.
2738 for (uint32_t col = 0; col < mtype.columns; col++)
2739 statement(name, "[", col, "] = stage_input.", name, "_", col, ";");
2740 }
2741 else
2742 {
2743 statement(name, " = stage_input.", name, ";");
2744 }
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002745 }
2746 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002747 });
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002748
2749 // Run the shader.
Hans-Kristian Arntzen06ca9ac2022-07-22 12:04:33 +02002750 if (execution.model == ExecutionModelVertex ||
2751 execution.model == ExecutionModelFragment ||
2752 execution.model == ExecutionModelGLCompute)
2753 {
2754 statement(get_inner_entry_point_name(), "();");
2755 }
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01002756 else
2757 SPIRV_CROSS_THROW("Unsupported shader stage.");
Robert Konrad95a716f2016-08-16 00:27:39 +02002758
Hans-Kristian Arntzen439fa9f2017-03-07 16:18:43 +01002759 // Copy stage outputs.
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01002760 if (require_output)
2761 {
2762 statement("SPIRV_Cross_Output stage_output;");
2763
2764 // Copy builtins from globals to return struct.
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002765 active_output_builtins.for_each_bit([&](uint32_t i) {
Hans-Kristian Arntzen17d88ca2017-05-04 10:10:30 +02002766 // PointSize doesn't exist in HLSL.
2767 if (i == BuiltInPointSize)
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002768 return;
Hans-Kristian Arntzen17d88ca2017-05-04 10:10:30 +02002769
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01002770 switch (static_cast<BuiltIn>(i))
2771 {
2772 case BuiltInClipDistance:
2773 for (uint32_t clip = 0; clip < clip_distance_count; clip++)
Hans-Kristian Arntzen4543dac2018-02-23 13:13:02 +01002774 statement("stage_output.gl_ClipDistance", clip / 4, ".", "xyzw"[clip & 3], " = gl_ClipDistance[",
2775 clip, "];");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01002776 break;
2777
2778 case BuiltInCullDistance:
2779 for (uint32_t cull = 0; cull < cull_distance_count; cull++)
Hans-Kristian Arntzen4543dac2018-02-23 13:13:02 +01002780 statement("stage_output.gl_CullDistance", cull / 4, ".", "xyzw"[cull & 3], " = gl_CullDistance[",
2781 cull, "];");
Hans-Kristian Arntzen114c2c52018-02-22 16:40:04 +01002782 break;
2783
2784 default:
2785 {
2786 auto builtin_expr = builtin_to_glsl(static_cast<BuiltIn>(i), StorageClassOutput);
2787 statement("stage_output.", builtin_expr, " = ", builtin_expr, ";");
2788 break;
2789 }
2790 }
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01002791 });
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01002792
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002793 ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
Hans-Kristian Arntzen2fb9aa22019-01-11 09:29:28 +01002794 auto &type = this->get<SPIRType>(var.basetype);
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002795 bool block = has_decoration(type.self, DecorationBlock);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002796
2797 if (var.storage != StorageClassOutput)
2798 return;
2799
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002800 if (!var.remapped_variable && type.pointer &&
2801 !is_builtin_variable(var) &&
2802 interface_variable_exists_in_entry_point(var.self))
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01002803 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002804 if (block)
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01002805 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002806 // I/O blocks need to flatten output.
2807 auto type_name = to_name(type.self);
2808 auto var_name = to_name(var.self);
2809 for (uint32_t mbr_idx = 0; mbr_idx < uint32_t(type.member_types.size()); mbr_idx++)
2810 {
2811 auto mbr_name = to_member_name(type, mbr_idx);
2812 auto flat_name = join(type_name, "_", mbr_name);
2813 statement("stage_output.", flat_name, " = ", var_name, ".", mbr_name, ";");
2814 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002815 }
2816 else
2817 {
Hans-Kristian Arntzend6b29ab2021-06-28 14:24:29 +02002818 auto name = to_name(var.self);
2819
2820 if (legacy && execution.model == ExecutionModelFragment)
2821 {
2822 string output_filler;
2823 for (uint32_t size = type.vecsize; size < 4; ++size)
2824 output_filler += ", 0.0";
2825
2826 statement("stage_output.", name, " = float4(", name, output_filler, ");");
2827 }
2828 else
2829 {
2830 statement("stage_output.", name, " = ", name, ";");
2831 }
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01002832 }
2833 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01002834 });
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01002835
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01002836 statement("return stage_output;");
2837 }
Robert Konrad80fcf552016-08-14 21:33:32 +02002838
2839 end_scope();
Robert Konradd2b29c92016-08-14 23:09:06 +02002840}
Robert Konrad80fcf552016-08-14 21:33:32 +02002841
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +02002842void CompilerHLSL::emit_fixup()
2843{
Hans-Kristian Arntzen7af0a5f2022-02-28 12:09:40 +01002844 if (is_vertex_like_shader() && active_output_builtins.get(BuiltInPosition))
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +02002845 {
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002846 // Do various mangling on the gl_Position.
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01002847 if (hlsl_options.shader_model <= 30)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002848 {
2849 statement("gl_Position.x = gl_Position.x - gl_HalfPixel.x * "
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02002850 "gl_Position.w;");
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002851 statement("gl_Position.y = gl_Position.y + gl_HalfPixel.y * "
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02002852 "gl_Position.w;");
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002853 }
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +02002854
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01002855 if (options.vertex.flip_vert_y)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002856 statement("gl_Position.y = -gl_Position.y;");
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01002857 if (options.vertex.fixup_clipspace)
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +02002858 statement("gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;");
2859 }
Hans-Kristian Arntzenbdfa97a2017-08-03 13:02:59 +02002860}
2861
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02002862void CompilerHLSL::emit_texture_op(const Instruction &i, bool sparse)
Robert Konradd2b29c92016-08-14 23:09:06 +02002863{
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02002864 if (sparse)
2865 SPIRV_CROSS_THROW("Sparse feedback not yet supported in HLSL.");
2866
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02002867 auto *ops = stream(i);
Robert Konradd2b29c92016-08-14 23:09:06 +02002868 auto op = static_cast<Op>(i.op);
2869 uint32_t length = i.length;
2870
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02002871 SmallVector<uint32_t> inherited_expressions;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01002872
Robert Konradd2b29c92016-08-14 23:09:06 +02002873 uint32_t result_type = ops[0];
2874 uint32_t id = ops[1];
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02002875 VariableID img = ops[2];
Robert Konradd2b29c92016-08-14 23:09:06 +02002876 uint32_t coord = ops[3];
2877 uint32_t dref = 0;
2878 uint32_t comp = 0;
2879 bool gather = false;
2880 bool proj = false;
2881 const uint32_t *opt = nullptr;
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02002882 auto *combined_image = maybe_get<SPIRCombinedImageSampler>(img);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02002883
2884 if (combined_image && has_decoration(img, DecorationNonUniform))
2885 {
2886 set_decoration(combined_image->image, DecorationNonUniform);
2887 set_decoration(combined_image->sampler, DecorationNonUniform);
2888 }
2889
2890 auto img_expr = to_non_uniform_aware_expression(combined_image ? combined_image->image : img);
Robert Konradd2b29c92016-08-14 23:09:06 +02002891
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01002892 inherited_expressions.push_back(coord);
2893
Robert Konradd2b29c92016-08-14 23:09:06 +02002894 switch (op)
2895 {
2896 case OpImageSampleDrefImplicitLod:
2897 case OpImageSampleDrefExplicitLod:
2898 dref = ops[4];
2899 opt = &ops[5];
2900 length -= 5;
2901 break;
2902
2903 case OpImageSampleProjDrefImplicitLod:
2904 case OpImageSampleProjDrefExplicitLod:
2905 dref = ops[4];
2906 proj = true;
2907 opt = &ops[5];
2908 length -= 5;
2909 break;
2910
2911 case OpImageDrefGather:
2912 dref = ops[4];
2913 opt = &ops[5];
2914 gather = true;
2915 length -= 5;
2916 break;
2917
2918 case OpImageGather:
2919 comp = ops[4];
2920 opt = &ops[5];
2921 gather = true;
2922 length -= 5;
2923 break;
2924
2925 case OpImageSampleProjImplicitLod:
2926 case OpImageSampleProjExplicitLod:
2927 opt = &ops[4];
2928 length -= 4;
2929 proj = true;
2930 break;
2931
Hans-Kristian Arntzenaeeb0e32017-12-01 13:28:51 +01002932 case OpImageQueryLod:
2933 opt = &ops[4];
2934 length -= 4;
2935 break;
2936
Robert Konradd2b29c92016-08-14 23:09:06 +02002937 default:
2938 opt = &ops[4];
2939 length -= 4;
2940 break;
2941 }
2942
2943 auto &imgtype = expression_type(img);
2944 uint32_t coord_components = 0;
2945 switch (imgtype.image.dim)
2946 {
2947 case spv::Dim1D:
2948 coord_components = 1;
2949 break;
2950 case spv::Dim2D:
2951 coord_components = 2;
2952 break;
2953 case spv::Dim3D:
2954 coord_components = 3;
2955 break;
2956 case spv::DimCube:
2957 coord_components = 3;
2958 break;
2959 case spv::DimBuffer:
2960 coord_components = 1;
2961 break;
2962 default:
2963 coord_components = 2;
2964 break;
2965 }
2966
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01002967 if (dref)
2968 inherited_expressions.push_back(dref);
2969
Robert Konradd2b29c92016-08-14 23:09:06 +02002970 if (imgtype.image.arrayed)
2971 coord_components++;
2972
2973 uint32_t bias = 0;
2974 uint32_t lod = 0;
2975 uint32_t grad_x = 0;
2976 uint32_t grad_y = 0;
2977 uint32_t coffset = 0;
2978 uint32_t offset = 0;
2979 uint32_t coffsets = 0;
2980 uint32_t sample = 0;
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02002981 uint32_t minlod = 0;
Robert Konradd2b29c92016-08-14 23:09:06 +02002982 uint32_t flags = 0;
2983
2984 if (length)
2985 {
2986 flags = opt[0];
2987 opt++;
2988 length--;
2989 }
2990
2991 auto test = [&](uint32_t &v, uint32_t flag) {
2992 if (length && (flags & flag))
2993 {
2994 v = *opt++;
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01002995 inherited_expressions.push_back(v);
Robert Konradd2b29c92016-08-14 23:09:06 +02002996 length--;
2997 }
2998 };
2999
3000 test(bias, ImageOperandsBiasMask);
3001 test(lod, ImageOperandsLodMask);
3002 test(grad_x, ImageOperandsGradMask);
3003 test(grad_y, ImageOperandsGradMask);
3004 test(coffset, ImageOperandsConstOffsetMask);
3005 test(offset, ImageOperandsOffsetMask);
3006 test(coffsets, ImageOperandsConstOffsetsMask);
3007 test(sample, ImageOperandsSampleMask);
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02003008 test(minlod, ImageOperandsMinLodMask);
Robert Konradd2b29c92016-08-14 23:09:06 +02003009
3010 string expr;
3011 string texop;
3012
Hans-Kristian Arntzenf171d822019-06-11 11:10:16 +02003013 if (minlod != 0)
3014 SPIRV_CROSS_THROW("MinLod texture operand not supported in HLSL.");
3015
Robert Konradd2b29c92016-08-14 23:09:06 +02003016 if (op == OpImageFetch)
Robert Konradbb9dbd42017-04-24 11:08:55 +02003017 {
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01003018 if (hlsl_options.shader_model < 40)
Robert Konradbb9dbd42017-04-24 11:08:55 +02003019 {
3020 SPIRV_CROSS_THROW("texelFetch is not supported in HLSL shader model 2/3.");
3021 }
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003022 texop += img_expr;
Robert Konradbb9dbd42017-04-24 11:08:55 +02003023 texop += ".Load";
3024 }
Hans-Kristian Arntzenaeeb0e32017-12-01 13:28:51 +01003025 else if (op == OpImageQueryLod)
3026 {
3027 texop += img_expr;
3028 texop += ".CalculateLevelOfDetail";
3029 }
Robert Konradd2b29c92016-08-14 23:09:06 +02003030 else
3031 {
Robert Konrad9aaf6b22017-04-21 11:40:24 +02003032 auto &imgformat = get<SPIRType>(imgtype.image.type);
3033 if (imgformat.basetype != SPIRType::Float)
3034 {
3035 SPIRV_CROSS_THROW("Sampling non-float textures is not supported in HLSL.");
3036 }
3037
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01003038 if (hlsl_options.shader_model >= 40)
Robert Konradc5953e02017-04-18 14:14:48 +02003039 {
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003040 texop += img_expr;
Robert Konradec84e882017-04-18 14:55:38 +02003041
Bill Hollingsfd252b22021-11-08 15:59:45 -05003042 if (is_depth_image(imgtype, img))
Hans-Kristian Arntzendbfa6862017-11-29 12:38:13 +01003043 {
3044 if (gather)
3045 {
3046 SPIRV_CROSS_THROW("GatherCmp does not exist in HLSL.");
3047 }
3048 else if (lod || grad_x || grad_y)
3049 {
3050 // Assume we want a fixed level, and the only thing we can get in HLSL is SampleCmpLevelZero.
3051 texop += ".SampleCmpLevelZero";
3052 }
3053 else
3054 texop += ".SampleCmp";
3055 }
Robert Konrad7d8be832017-04-21 17:52:04 +02003056 else if (gather)
James Ross-Gowan02e6be72017-09-12 07:20:01 +10003057 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02003058 uint32_t comp_num = evaluate_constant_u32(comp);
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01003059 if (hlsl_options.shader_model >= 50)
James Ross-Gowan02e6be72017-09-12 07:20:01 +10003060 {
3061 switch (comp_num)
3062 {
3063 case 0:
3064 texop += ".GatherRed";
3065 break;
3066 case 1:
3067 texop += ".GatherGreen";
3068 break;
3069 case 2:
3070 texop += ".GatherBlue";
3071 break;
3072 case 3:
3073 texop += ".GatherAlpha";
3074 break;
3075 default:
3076 SPIRV_CROSS_THROW("Invalid component.");
3077 }
3078 }
3079 else
3080 {
3081 if (comp_num == 0)
3082 texop += ".Gather";
3083 else
3084 SPIRV_CROSS_THROW("HLSL shader model 4 can only gather from the red component.");
3085 }
3086 }
Robert Konradde41ebf2017-04-20 16:04:02 +02003087 else if (bias)
Robert Konradec84e882017-04-18 14:55:38 +02003088 texop += ".SampleBias";
Robert Konradec84e882017-04-18 14:55:38 +02003089 else if (grad_x || grad_y)
3090 texop += ".SampleGrad";
3091 else if (lod)
3092 texop += ".SampleLevel";
3093 else
3094 texop += ".Sample";
Robert Konradc5953e02017-04-18 14:14:48 +02003095 }
3096 else
3097 {
Robert Konradff12d572017-04-21 14:35:30 +02003098 switch (imgtype.image.dim)
3099 {
3100 case Dim1D:
3101 texop += "tex1D";
3102 break;
3103 case Dim2D:
3104 texop += "tex2D";
3105 break;
3106 case Dim3D:
3107 texop += "tex3D";
3108 break;
3109 case DimCube:
Robert Konrad84466312017-04-21 14:54:03 +02003110 texop += "texCUBE";
3111 break;
Robert Konradff12d572017-04-21 14:35:30 +02003112 case DimRect:
3113 case DimBuffer:
3114 case DimSubpassData:
Robert Konrad84466312017-04-21 14:54:03 +02003115 SPIRV_CROSS_THROW("Buffer texture support is not yet implemented for HLSL"); // TODO
Hans-Kristian Arntzen08b3c672017-05-09 09:30:30 +02003116 default:
3117 SPIRV_CROSS_THROW("Invalid dimension.");
Robert Konradff12d572017-04-21 14:35:30 +02003118 }
Robert Konradd2b29c92016-08-14 23:09:06 +02003119
Robert Konradc5953e02017-04-18 14:14:48 +02003120 if (gather)
Robert Konradec84e882017-04-18 14:55:38 +02003121 SPIRV_CROSS_THROW("textureGather is not supported in HLSL shader model 2/3.");
Robert Konrad61207512017-04-20 16:15:46 +02003122 if (offset || coffset)
Robert Konradec84e882017-04-18 14:55:38 +02003123 SPIRV_CROSS_THROW("textureOffset is not supported in HLSL shader model 2/3.");
rdb18893ba2020-10-31 12:06:15 +01003124
Robert Konradc5953e02017-04-18 14:14:48 +02003125 if (grad_x || grad_y)
Robert Konradec84e882017-04-18 14:55:38 +02003126 texop += "grad";
rdb18893ba2020-10-31 12:06:15 +01003127 else if (lod)
Robert Konradec84e882017-04-18 14:55:38 +02003128 texop += "lod";
rdb18893ba2020-10-31 12:06:15 +01003129 else if (bias)
Robert Konradec84e882017-04-18 14:55:38 +02003130 texop += "bias";
rdb18893ba2020-10-31 12:06:15 +01003131 else if (proj || dref)
3132 texop += "proj";
Robert Konradc5953e02017-04-18 14:14:48 +02003133 }
Robert Konradd2b29c92016-08-14 23:09:06 +02003134 }
3135
Robert Konradd2b29c92016-08-14 23:09:06 +02003136 expr += texop;
Robert Konrad61207512017-04-20 16:15:46 +02003137 expr += "(";
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01003138 if (hlsl_options.shader_model < 40)
Robert Konrad111a30a2017-05-31 16:53:43 +02003139 {
3140 if (combined_image)
3141 SPIRV_CROSS_THROW("Separate images/samplers are not supported in HLSL shader model 2/3.");
3142 expr += to_expression(img);
3143 }
3144 else if (op != OpImageFetch)
Robert Konrad61207512017-04-20 16:15:46 +02003145 {
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003146 string sampler_expr;
3147 if (combined_image)
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02003148 sampler_expr = to_non_uniform_aware_expression(combined_image->sampler);
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003149 else
Hans-Kristian Arntzen686ac682017-05-07 13:22:16 +02003150 sampler_expr = to_sampler_expression(img);
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003151 expr += sampler_expr;
Robert Konradc5953e02017-04-18 14:14:48 +02003152 }
Robert Konradd2b29c92016-08-14 23:09:06 +02003153
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003154 auto swizzle = [](uint32_t comps, uint32_t in_comps) -> const char * {
Robert Konradd2b29c92016-08-14 23:09:06 +02003155 if (comps == in_comps)
3156 return "";
3157
3158 switch (comps)
3159 {
3160 case 1:
3161 return ".x";
3162 case 2:
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003163 return ".xy";
Robert Konradd2b29c92016-08-14 23:09:06 +02003164 case 3:
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003165 return ".xyz";
Robert Konradd2b29c92016-08-14 23:09:06 +02003166 default:
3167 return "";
3168 }
3169 };
3170
3171 bool forward = should_forward(coord);
3172
3173 // The IR can give us more components than we need, so chop them off as needed.
Hans-Kristian Arntzen18a4acc2019-01-28 09:39:45 +01003174 string coord_expr;
Hans-Kristian Arntzene4d5c612019-04-03 10:50:32 +02003175 auto &coord_type = expression_type(coord);
3176 if (coord_components != coord_type.vecsize)
Hans-Kristian Arntzen18a4acc2019-01-28 09:39:45 +01003177 coord_expr = to_enclosed_expression(coord) + swizzle(coord_components, expression_type(coord).vecsize);
3178 else
3179 coord_expr = to_expression(coord);
Robert Konradd2b29c92016-08-14 23:09:06 +02003180
Hans-Kristian Arntzen18a4acc2019-01-28 09:39:45 +01003181 if (proj && hlsl_options.shader_model >= 40) // Legacy HLSL has "proj" operations which do this for us.
3182 coord_expr = coord_expr + " / " + to_extract_component_expression(coord, coord_components);
Robert Konradfd9b5892017-04-20 13:37:38 +02003183
Hans-Kristian Arntzend13dc0c2020-06-16 12:54:22 +02003184 if (hlsl_options.shader_model < 40)
Robert Konrad1fe652d2017-04-21 09:46:58 +02003185 {
rdb18893ba2020-10-31 12:06:15 +01003186 if (dref)
3187 {
3188 if (imgtype.image.dim != spv::Dim1D && imgtype.image.dim != spv::Dim2D)
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01003189 {
3190 SPIRV_CROSS_THROW(
3191 "Depth comparison is only supported for 1D and 2D textures in HLSL shader model 2/3.");
3192 }
rdb18893ba2020-10-31 12:06:15 +01003193
3194 if (grad_x || grad_y)
3195 SPIRV_CROSS_THROW("Depth comparison is not supported for grad sampling in HLSL shader model 2/3.");
3196
3197 for (uint32_t size = coord_components; size < 2; ++size)
3198 coord_expr += ", 0.0";
3199
3200 forward = forward && should_forward(dref);
3201 coord_expr += ", " + to_expression(dref);
3202 }
3203 else if (lod || bias || proj)
3204 {
3205 for (uint32_t size = coord_components; size < 3; ++size)
3206 coord_expr += ", 0.0";
3207 }
Robert Konrad1fe652d2017-04-21 09:46:58 +02003208
Hans-Kristian Arntzend13dc0c2020-06-16 12:54:22 +02003209 if (lod)
Robert Konradff12d572017-04-21 14:35:30 +02003210 {
rdb18893ba2020-10-31 12:06:15 +01003211 coord_expr = "float4(" + coord_expr + ", " + to_expression(lod) + ")";
Robert Konradff12d572017-04-21 14:35:30 +02003212 }
rdb18893ba2020-10-31 12:06:15 +01003213 else if (bias)
Hans-Kristian Arntzend13dc0c2020-06-16 12:54:22 +02003214 {
rdb18893ba2020-10-31 12:06:15 +01003215 coord_expr = "float4(" + coord_expr + ", " + to_expression(bias) + ")";
Hans-Kristian Arntzend13dc0c2020-06-16 12:54:22 +02003216 }
rdb18893ba2020-10-31 12:06:15 +01003217 else if (proj)
Hans-Kristian Arntzend13dc0c2020-06-16 12:54:22 +02003218 {
Hans-Kristian Arntzen6fc2a052020-11-08 13:59:52 +01003219 coord_expr = "float4(" + coord_expr + ", " + to_extract_component_expression(coord, coord_components) + ")";
rdb18893ba2020-10-31 12:06:15 +01003220 }
3221 else if (dref)
3222 {
3223 // A "normal" sample gets fed into tex2Dproj as well, because the
3224 // regular tex2D accepts only two coordinates.
3225 coord_expr = "float4(" + coord_expr + ", 1.0)";
Hans-Kristian Arntzend13dc0c2020-06-16 12:54:22 +02003226 }
3227
rdb18893ba2020-10-31 12:06:15 +01003228 if (!!lod + !!bias + !!proj > 1)
Hans-Kristian Arntzend13dc0c2020-06-16 12:54:22 +02003229 SPIRV_CROSS_THROW("Legacy HLSL can only use one of lod/bias/proj modifiers.");
Robert Konrad1fe652d2017-04-21 09:46:58 +02003230 }
3231
Robert Konradbb9dbd42017-04-24 11:08:55 +02003232 if (op == OpImageFetch)
3233 {
Hans-Kristian Arntzend93807a2018-04-30 10:53:21 +02003234 if (imgtype.image.dim != DimBuffer && !imgtype.image.ms)
3235 coord_expr =
Hans-Kristian Arntzene4d5c612019-04-03 10:50:32 +02003236 join("int", coord_components + 1, "(", coord_expr, ", ", lod ? to_expression(lod) : string("0"), ")");
Robert Konradbb9dbd42017-04-24 11:08:55 +02003237 }
Hans-Kristian Arntzenaeeb0e32017-12-01 13:28:51 +01003238 else
Robert Konradbb9dbd42017-04-24 11:08:55 +02003239 expr += ", ";
Robert Konrad7d8be832017-04-21 17:52:04 +02003240 expr += coord_expr;
Bill Hollings012cb252017-04-25 11:25:50 -04003241
rdb18893ba2020-10-31 12:06:15 +01003242 if (dref && hlsl_options.shader_model >= 40)
Robert Konradd2b29c92016-08-14 23:09:06 +02003243 {
3244 forward = forward && should_forward(dref);
Robert Konradd2b29c92016-08-14 23:09:06 +02003245 expr += ", ";
Hans-Kristian Arntzen18a4acc2019-01-28 09:39:45 +01003246
3247 if (proj)
3248 expr += to_enclosed_expression(dref) + " / " + to_extract_component_expression(coord, coord_components);
3249 else
3250 expr += to_expression(dref);
Robert Konradd2b29c92016-08-14 23:09:06 +02003251 }
3252
Hans-Kristian Arntzendbfa6862017-11-29 12:38:13 +01003253 if (!dref && (grad_x || grad_y))
Robert Konradd2b29c92016-08-14 23:09:06 +02003254 {
3255 forward = forward && should_forward(grad_x);
3256 forward = forward && should_forward(grad_y);
3257 expr += ", ";
3258 expr += to_expression(grad_x);
3259 expr += ", ";
3260 expr += to_expression(grad_y);
3261 }
3262
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01003263 if (!dref && lod && hlsl_options.shader_model >= 40 && op != OpImageFetch)
Robert Konradd2b29c92016-08-14 23:09:06 +02003264 {
3265 forward = forward && should_forward(lod);
3266 expr += ", ";
3267 expr += to_expression(lod);
3268 }
3269
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01003270 if (!dref && bias && hlsl_options.shader_model >= 40)
Robert Konradec84e882017-04-18 14:55:38 +02003271 {
3272 forward = forward && should_forward(bias);
3273 expr += ", ";
3274 expr += to_expression(bias);
3275 }
3276
Robert Konradd2b29c92016-08-14 23:09:06 +02003277 if (coffset)
3278 {
3279 forward = forward && should_forward(coffset);
3280 expr += ", ";
3281 expr += to_expression(coffset);
3282 }
3283 else if (offset)
3284 {
3285 forward = forward && should_forward(offset);
3286 expr += ", ";
3287 expr += to_expression(offset);
3288 }
3289
Robert Konradd2b29c92016-08-14 23:09:06 +02003290 if (sample)
3291 {
3292 expr += ", ";
3293 expr += to_expression(sample);
3294 }
3295
3296 expr += ")";
3297
rdb18893ba2020-10-31 12:06:15 +01003298 if (dref && hlsl_options.shader_model < 40)
3299 expr += ".x";
3300
Hans-Kristian Arntzenaeeb0e32017-12-01 13:28:51 +01003301 if (op == OpImageQueryLod)
3302 {
3303 // This is rather awkward.
3304 // textureQueryLod returns two values, the "accessed level",
3305 // as well as the actual LOD lambda.
3306 // As far as I can tell, there is no way to get the .x component
3307 // according to GLSL spec, and it depends on the sampler itself.
3308 // Just assume X == Y, so we will need to splat the result to a float2.
3309 statement("float _", id, "_tmp = ", expr, ";");
Hans-Kristian Arntzen4bc87292019-07-24 11:34:28 +02003310 statement("float2 _", id, " = _", id, "_tmp.xx;");
3311 set<SPIRExpression>(id, join("_", id), result_type, true);
Hans-Kristian Arntzenaeeb0e32017-12-01 13:28:51 +01003312 }
3313 else
3314 {
3315 emit_op(result_type, id, expr, forward, false);
3316 }
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01003317
3318 for (auto &inherit : inherited_expressions)
3319 inherit_expression_dependencies(id, inherit);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01003320
3321 switch (op)
3322 {
3323 case OpImageSampleDrefImplicitLod:
3324 case OpImageSampleImplicitLod:
3325 case OpImageSampleProjImplicitLod:
3326 case OpImageSampleProjDrefImplicitLod:
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01003327 register_control_dependent_expression(id);
3328 break;
3329
3330 default:
3331 break;
3332 }
Robert Konrad80fcf552016-08-14 21:33:32 +02003333}
3334
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003335string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
3336{
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01003337 const auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003338
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01003339 // We can remap push constant blocks, even if they don't have any binding decoration.
3340 if (type.storage != StorageClassPushConstant && !has_decoration(var.self, DecorationBinding))
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003341 return "";
3342
msiglreithd096f5c2017-11-27 16:00:56 +01003343 char space = '\0';
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003344
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01003345 HLSLBindingFlagBits resource_flags = HLSL_BINDING_AUTO_NONE_BIT;
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003346
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003347 switch (type.basetype)
3348 {
3349 case SPIRType::SampledImage:
msiglreithd096f5c2017-11-27 16:00:56 +01003350 space = 't'; // SRV
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003351 resource_flags = HLSL_BINDING_AUTO_SRV_BIT;
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003352 break;
3353
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02003354 case SPIRType::Image:
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01003355 if (type.image.sampled == 2 && type.image.dim != DimSubpassData)
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003356 {
Hans-Kristian Arntzen28bf9052020-04-03 11:21:41 +02003357 if (has_decoration(var.self, DecorationNonWritable) && hlsl_options.nonwritable_uav_texture_as_srv)
3358 {
3359 space = 't'; // SRV
3360 resource_flags = HLSL_BINDING_AUTO_SRV_BIT;
3361 }
3362 else
3363 {
3364 space = 'u'; // UAV
3365 resource_flags = HLSL_BINDING_AUTO_UAV_BIT;
3366 }
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003367 }
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02003368 else
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003369 {
msiglreithd096f5c2017-11-27 16:00:56 +01003370 space = 't'; // SRV
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003371 resource_flags = HLSL_BINDING_AUTO_SRV_BIT;
3372 }
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02003373 break;
3374
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003375 case SPIRType::Sampler:
msiglreithd096f5c2017-11-27 16:00:56 +01003376 space = 's';
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003377 resource_flags = HLSL_BINDING_AUTO_SAMPLER_BIT;
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003378 break;
3379
Konstantin Pail251361b2022-03-15 21:54:29 +03003380 case SPIRType::AccelerationStructure:
3381 space = 't'; // SRV
3382 resource_flags = HLSL_BINDING_AUTO_SRV_BIT;
3383 break;
3384
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003385 case SPIRType::Struct:
3386 {
3387 auto storage = type.storage;
3388 if (storage == StorageClassUniform)
3389 {
3390 if (has_decoration(type.self, DecorationBufferBlock))
Hans-Kristian Arntzencc532cb2017-12-11 13:55:26 +01003391 {
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02003392 Bitset flags = ir.get_buffer_block_flags(var);
Bryan Bernhart17bccc92020-05-27 13:08:15 -07003393 bool is_readonly = flags.get(DecorationNonWritable) && !is_hlsl_force_storage_buffer_as_uav(var.self);
msiglreithd096f5c2017-11-27 16:00:56 +01003394 space = is_readonly ? 't' : 'u'; // UAV
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003395 resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
Hans-Kristian Arntzencc532cb2017-12-11 13:55:26 +01003396 }
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003397 else if (has_decoration(type.self, DecorationBlock))
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003398 {
msiglreithd096f5c2017-11-27 16:00:56 +01003399 space = 'b'; // Constant buffers
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003400 resource_flags = HLSL_BINDING_AUTO_CBV_BIT;
3401 }
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003402 }
3403 else if (storage == StorageClassPushConstant)
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003404 {
msiglreithd096f5c2017-11-27 16:00:56 +01003405 space = 'b'; // Constant buffers
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003406 resource_flags = HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT;
3407 }
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02003408 else if (storage == StorageClassStorageBuffer)
Hans-Kristian Arntzen4e7777c2019-01-30 13:31:17 +01003409 {
3410 // UAV or SRV depending on readonly flag.
3411 Bitset flags = ir.get_buffer_block_flags(var);
Bryan Bernhart17bccc92020-05-27 13:08:15 -07003412 bool is_readonly = flags.get(DecorationNonWritable) && !is_hlsl_force_storage_buffer_as_uav(var.self);
Hans-Kristian Arntzen4e7777c2019-01-30 13:31:17 +01003413 space = is_readonly ? 't' : 'u';
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003414 resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
Hans-Kristian Arntzen4e7777c2019-01-30 13:31:17 +01003415 }
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003416
3417 break;
3418 }
3419 default:
3420 break;
3421 }
3422
3423 if (!space)
3424 return "";
3425
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01003426 uint32_t desc_set =
3427 resource_flags == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT ? ResourceBindingPushConstantDescriptorSet : 0u;
3428 uint32_t binding = resource_flags == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT ? ResourceBindingPushConstantBinding : 0u;
3429
3430 if (has_decoration(var.self, DecorationBinding))
3431 binding = get_decoration(var.self, DecorationBinding);
3432 if (has_decoration(var.self, DecorationDescriptorSet))
3433 desc_set = get_decoration(var.self, DecorationDescriptorSet);
3434
3435 return to_resource_register(resource_flags, space, binding, desc_set);
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003436}
3437
3438string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var)
3439{
3440 // For combined image samplers.
3441 if (!has_decoration(var.self, DecorationBinding))
3442 return "";
Amer Koleciadebd5e2017-11-15 18:07:13 +01003443
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003444 return to_resource_register(HLSL_BINDING_AUTO_SAMPLER_BIT, 's', get_decoration(var.self, DecorationBinding),
msiglreithd096f5c2017-11-27 16:00:56 +01003445 get_decoration(var.self, DecorationDescriptorSet));
3446}
3447
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01003448void CompilerHLSL::remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding)
msiglreithd096f5c2017-11-27 16:00:56 +01003449{
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01003450 auto itr = resource_bindings.find({ get_execution_model(), desc_set, binding });
3451 if (itr != end(resource_bindings))
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003452 {
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01003453 auto &remap = itr->second;
3454 remap.second = true;
3455
3456 switch (type)
3457 {
3458 case HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT:
3459 case HLSL_BINDING_AUTO_CBV_BIT:
3460 desc_set = remap.first.cbv.register_space;
3461 binding = remap.first.cbv.register_binding;
3462 break;
3463
3464 case HLSL_BINDING_AUTO_SRV_BIT:
3465 desc_set = remap.first.srv.register_space;
3466 binding = remap.first.srv.register_binding;
3467 break;
3468
3469 case HLSL_BINDING_AUTO_SAMPLER_BIT:
3470 desc_set = remap.first.sampler.register_space;
3471 binding = remap.first.sampler.register_binding;
3472 break;
3473
3474 case HLSL_BINDING_AUTO_UAV_BIT:
3475 desc_set = remap.first.uav.register_space;
3476 binding = remap.first.uav.register_binding;
3477 break;
3478
3479 default:
3480 break;
3481 }
3482 }
3483}
3484
3485string CompilerHLSL::to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t space_set)
3486{
3487 if ((flag & resource_binding_flags) == 0)
3488 {
3489 remap_hlsl_resource_binding(flag, space_set, binding);
3490
3491 // The push constant block did not have a binding, and there were no remap for it,
3492 // so, declare without register binding.
3493 if (flag == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT && space_set == ResourceBindingPushConstantDescriptorSet)
3494 return "";
3495
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003496 if (hlsl_options.shader_model >= 51)
3497 return join(" : register(", space, binding, ", space", space_set, ")");
3498 else
3499 return join(" : register(", space, binding, ")");
3500 }
Amer Koleciadebd5e2017-11-15 18:07:13 +01003501 else
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01003502 return "";
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003503}
3504
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003505void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var)
Robert Konradc3268c92017-01-24 09:23:22 +01003506{
Robert Konradc5953e02017-04-18 14:14:48 +02003507 auto &type = get<SPIRType>(var.basetype);
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003508 switch (type.basetype)
3509 {
3510 case SPIRType::SampledImage:
3511 case SPIRType::Image:
Robert Konradc5953e02017-04-18 14:14:48 +02003512 {
Hans-Kristian Arntzen10dfaf72018-06-25 10:04:14 +02003513 bool is_coherent = false;
3514 if (type.basetype == SPIRType::Image && type.image.sampled == 2)
3515 is_coherent = has_decoration(var.self, DecorationCoherent);
3516
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02003517 statement(is_coherent ? "globallycoherent " : "", image_type_hlsl_modern(type, var.self), " ",
3518 to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";");
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003519
Hans-Kristian Arntzene8d5d712017-08-21 10:01:03 +02003520 if (type.basetype == SPIRType::SampledImage && type.image.dim != DimBuffer)
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003521 {
3522 // For combined image samplers, also emit a combined image sampler.
Bill Hollingsfd252b22021-11-08 15:59:45 -05003523 if (is_depth_image(type, var.self))
Hans-Kristian Arntzend9c09482018-01-04 12:15:55 +01003524 statement("SamplerComparisonState ", to_sampler_expression(var.self), type_to_array_glsl(type),
3525 to_resource_binding_sampler(var), ";");
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003526 else
Hans-Kristian Arntzend9c09482018-01-04 12:15:55 +01003527 statement("SamplerState ", to_sampler_expression(var.self), type_to_array_glsl(type),
3528 to_resource_binding_sampler(var), ";");
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003529 }
3530 break;
Robert Konradc5953e02017-04-18 14:14:48 +02003531 }
Robert Konrad1fe652d2017-04-21 09:46:58 +02003532
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003533 case SPIRType::Sampler:
Hans-Kristian Arntzene0447322018-07-04 14:25:10 +02003534 if (comparison_ids.count(var.self))
Hans-Kristian Arntzend9c09482018-01-04 12:15:55 +01003535 statement("SamplerComparisonState ", to_name(var.self), type_to_array_glsl(type), to_resource_binding(var),
3536 ";");
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003537 else
Hans-Kristian Arntzenc7f4b152018-01-04 11:05:40 +01003538 statement("SamplerState ", to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";");
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003539 break;
3540
3541 default:
Hans-Kristian Arntzen620da7b2017-06-17 10:15:32 +02003542 statement(variable_decl(var), to_resource_binding(var), ";");
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003543 break;
3544 }
3545}
3546
3547void CompilerHLSL::emit_legacy_uniform(const SPIRVariable &var)
3548{
3549 auto &type = get<SPIRType>(var.basetype);
3550 switch (type.basetype)
3551 {
3552 case SPIRType::Sampler:
3553 case SPIRType::Image:
3554 SPIRV_CROSS_THROW("Separate image and samplers not supported in legacy HLSL.");
3555
3556 default:
3557 statement(variable_decl(var), ";");
3558 break;
3559 }
3560}
3561
3562void CompilerHLSL::emit_uniform(const SPIRVariable &var)
3563{
3564 add_resource_name(var.self);
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01003565 if (hlsl_options.shader_model >= 40)
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +02003566 emit_modern_uniform(var);
3567 else
3568 emit_legacy_uniform(var);
Robert Konradc3268c92017-01-24 09:23:22 +01003569}
3570
Hans-Kristian Arntzen5e5d1c22020-04-21 23:27:33 +02003571bool CompilerHLSL::emit_complex_bitcast(uint32_t, uint32_t, uint32_t)
3572{
3573 return false;
3574}
3575
Robert Konrada7e2a692017-03-24 14:13:59 +01003576string CompilerHLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
3577{
3578 if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
3579 return type_to_glsl(out_type);
3580 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Int64)
3581 return type_to_glsl(out_type);
3582 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
3583 return "asuint";
3584 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::UInt)
3585 return type_to_glsl(out_type);
3586 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::UInt64)
3587 return type_to_glsl(out_type);
3588 else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
3589 return "asint";
3590 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
3591 return "asfloat";
3592 else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int)
3593 return "asfloat";
3594 else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double)
3595 SPIRV_CROSS_THROW("Double to Int64 is not supported in HLSL.");
3596 else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double)
3597 SPIRV_CROSS_THROW("Double to UInt64 is not supported in HLSL.");
3598 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64)
3599 return "asdouble";
3600 else if (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64)
3601 return "asdouble";
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003602 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
3603 {
3604 if (!requires_explicit_fp16_packing)
3605 {
3606 requires_explicit_fp16_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003607 force_recompile();
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003608 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003609 return "spvUnpackFloat2x16";
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003610 }
3611 else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Half && in_type.vecsize == 2)
3612 {
3613 if (!requires_explicit_fp16_packing)
3614 {
3615 requires_explicit_fp16_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003616 force_recompile();
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003617 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003618 return "spvPackFloat2x16";
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003619 }
Pedro J. Estébanezd8c5e392022-06-08 22:13:51 +02003620 else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Half)
3621 {
3622 if (hlsl_options.shader_model < 40)
3623 SPIRV_CROSS_THROW("Half to UShort requires Shader Model 4.");
3624 return "(" + type_to_glsl(out_type) + ")f32tof16";
3625 }
3626 else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort)
3627 {
3628 if (hlsl_options.shader_model < 40)
3629 SPIRV_CROSS_THROW("UShort to Half requires Shader Model 4.");
3630 return "(" + type_to_glsl(out_type) + ")f16tof32";
3631 }
Robert Konrada7e2a692017-03-24 14:13:59 +01003632 else
3633 return "";
3634}
3635
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003636void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t count)
3637{
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01003638 auto op = static_cast<GLSLstd450>(eop);
3639
3640 // If we need to do implicit bitcasts, make sure we do it with the correct type.
3641 uint32_t integer_width = get_integer_width_for_glsl_instruction(op, args, count);
3642 auto int_type = to_signed_basetype(integer_width);
3643 auto uint_type = to_unsigned_basetype(integer_width);
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003644
Hans-Kristian Arntzen31be74a2022-03-03 11:04:45 +01003645 op = get_remapped_glsl_op(op);
3646
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003647 switch (op)
3648 {
3649 case GLSLstd450InverseSqrt:
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003650 emit_unary_func_op(result_type, id, args[0], "rsqrt");
3651 break;
Robert Konrade7b02582017-03-24 13:58:39 +01003652
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003653 case GLSLstd450Fract:
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003654 emit_unary_func_op(result_type, id, args[0], "frac");
3655 break;
Robert Konrade7b02582017-03-24 13:58:39 +01003656
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003657 case GLSLstd450RoundEven:
rdb854f5662020-11-03 21:04:22 +01003658 if (hlsl_options.shader_model < 40)
3659 SPIRV_CROSS_THROW("roundEven is not supported in HLSL shader model 2/3.");
3660 emit_unary_func_op(result_type, id, args[0], "round");
3661 break;
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01003662
3663 case GLSLstd450Acosh:
3664 case GLSLstd450Asinh:
3665 case GLSLstd450Atanh:
3666 SPIRV_CROSS_THROW("Inverse hyperbolics are not supported on HLSL.");
3667
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003668 case GLSLstd450FMix:
3669 case GLSLstd450IMix:
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003670 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "lerp");
3671 break;
Robert Konrade7b02582017-03-24 13:58:39 +01003672
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003673 case GLSLstd450Atan2:
James Ross-Gowan8805d082017-09-24 02:45:33 +10003674 emit_binary_func_op(result_type, id, args[0], args[1], "atan2");
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003675 break;
Robert Konrade7b02582017-03-24 13:58:39 +01003676
3677 case GLSLstd450Fma:
3678 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "mad");
3679 break;
3680
3681 case GLSLstd450InterpolateAtCentroid:
3682 emit_unary_func_op(result_type, id, args[0], "EvaluateAttributeAtCentroid");
3683 break;
3684 case GLSLstd450InterpolateAtSample:
3685 emit_binary_func_op(result_type, id, args[0], args[1], "EvaluateAttributeAtSample");
3686 break;
3687 case GLSLstd450InterpolateAtOffset:
3688 emit_binary_func_op(result_type, id, args[0], args[1], "EvaluateAttributeSnapped");
3689 break;
3690
Hans-Kristian Arntzen6c7c6802017-11-27 14:24:30 +01003691 case GLSLstd450PackHalf2x16:
3692 if (!requires_fp16_packing)
3693 {
3694 requires_fp16_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003695 force_recompile();
Hans-Kristian Arntzen6c7c6802017-11-27 14:24:30 +01003696 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003697 emit_unary_func_op(result_type, id, args[0], "spvPackHalf2x16");
Hans-Kristian Arntzen6c7c6802017-11-27 14:24:30 +01003698 break;
3699
3700 case GLSLstd450UnpackHalf2x16:
3701 if (!requires_fp16_packing)
3702 {
3703 requires_fp16_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003704 force_recompile();
Hans-Kristian Arntzen6c7c6802017-11-27 14:24:30 +01003705 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003706 emit_unary_func_op(result_type, id, args[0], "spvUnpackHalf2x16");
Hans-Kristian Arntzen6c7c6802017-11-27 14:24:30 +01003707 break;
3708
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01003709 case GLSLstd450PackSnorm4x8:
3710 if (!requires_snorm8_packing)
3711 {
3712 requires_snorm8_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003713 force_recompile();
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01003714 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003715 emit_unary_func_op(result_type, id, args[0], "spvPackSnorm4x8");
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01003716 break;
3717
3718 case GLSLstd450UnpackSnorm4x8:
3719 if (!requires_snorm8_packing)
3720 {
3721 requires_snorm8_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003722 force_recompile();
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01003723 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003724 emit_unary_func_op(result_type, id, args[0], "spvUnpackSnorm4x8");
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01003725 break;
3726
3727 case GLSLstd450PackUnorm4x8:
3728 if (!requires_unorm8_packing)
3729 {
3730 requires_unorm8_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003731 force_recompile();
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01003732 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003733 emit_unary_func_op(result_type, id, args[0], "spvPackUnorm4x8");
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01003734 break;
3735
3736 case GLSLstd450UnpackUnorm4x8:
3737 if (!requires_unorm8_packing)
3738 {
3739 requires_unorm8_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003740 force_recompile();
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01003741 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003742 emit_unary_func_op(result_type, id, args[0], "spvUnpackUnorm4x8");
Hans-Kristian Arntzen719ba632017-11-27 14:44:21 +01003743 break;
3744
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01003745 case GLSLstd450PackSnorm2x16:
3746 if (!requires_snorm16_packing)
3747 {
3748 requires_snorm16_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003749 force_recompile();
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01003750 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003751 emit_unary_func_op(result_type, id, args[0], "spvPackSnorm2x16");
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01003752 break;
3753
3754 case GLSLstd450UnpackSnorm2x16:
3755 if (!requires_snorm16_packing)
3756 {
3757 requires_snorm16_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003758 force_recompile();
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01003759 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003760 emit_unary_func_op(result_type, id, args[0], "spvUnpackSnorm2x16");
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01003761 break;
3762
3763 case GLSLstd450PackUnorm2x16:
3764 if (!requires_unorm16_packing)
3765 {
3766 requires_unorm16_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003767 force_recompile();
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01003768 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003769 emit_unary_func_op(result_type, id, args[0], "spvPackUnorm2x16");
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01003770 break;
3771
3772 case GLSLstd450UnpackUnorm2x16:
3773 if (!requires_unorm16_packing)
3774 {
3775 requires_unorm16_packing = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003776 force_recompile();
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01003777 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003778 emit_unary_func_op(result_type, id, args[0], "spvUnpackUnorm2x16");
Hans-Kristian Arntzen656af7e2017-11-27 15:03:40 +01003779 break;
3780
Hans-Kristian Arntzene27f5772017-11-27 15:06:15 +01003781 case GLSLstd450PackDouble2x32:
3782 case GLSLstd450UnpackDouble2x32:
3783 SPIRV_CROSS_THROW("packDouble2x32/unpackDouble2x32 not supported in HLSL.");
3784
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01003785 case GLSLstd450FindILsb:
Hans-Kristian Arntzen932ee0e2019-07-12 10:57:56 +02003786 {
3787 auto basetype = expression_type(args[0]).basetype;
3788 emit_unary_func_op_cast(result_type, id, args[0], "firstbitlow", basetype, basetype);
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01003789 break;
Hans-Kristian Arntzen932ee0e2019-07-12 10:57:56 +02003790 }
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01003791
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01003792 case GLSLstd450FindSMsb:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01003793 emit_unary_func_op_cast(result_type, id, args[0], "firstbithigh", int_type, int_type);
3794 break;
3795
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01003796 case GLSLstd450FindUMsb:
Hans-Kristian Arntzeneeb3f242019-03-27 11:53:47 +01003797 emit_unary_func_op_cast(result_type, id, args[0], "firstbithigh", uint_type, uint_type);
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01003798 break;
3799
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01003800 case GLSLstd450MatrixInverse:
3801 {
3802 auto &type = get<SPIRType>(result_type);
3803 if (type.vecsize == 2 && type.columns == 2)
3804 {
3805 if (!requires_inverse_2x2)
3806 {
3807 requires_inverse_2x2 = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003808 force_recompile();
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01003809 }
3810 }
3811 else if (type.vecsize == 3 && type.columns == 3)
3812 {
3813 if (!requires_inverse_3x3)
3814 {
3815 requires_inverse_3x3 = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003816 force_recompile();
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01003817 }
3818 }
3819 else if (type.vecsize == 4 && type.columns == 4)
3820 {
3821 if (!requires_inverse_4x4)
3822 {
3823 requires_inverse_4x4 = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02003824 force_recompile();
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01003825 }
3826 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003827 emit_unary_func_op(result_type, id, args[0], "spvInverse");
Hans-Kristian Arntzenb380a212018-02-23 16:36:12 +01003828 break;
3829 }
3830
Hans-Kristian Arntzenff874192019-06-28 11:19:19 +02003831 case GLSLstd450Normalize:
3832 // HLSL does not support scalar versions here.
3833 if (expression_type(args[0]).vecsize == 1)
3834 {
3835 // Returns -1 or 1 for valid input, sign() does the job.
3836 emit_unary_func_op(result_type, id, args[0], "sign");
3837 }
3838 else
3839 CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count);
3840 break;
3841
Hans-Kristian Arntzen041f1032019-07-03 12:24:58 +02003842 case GLSLstd450Reflect:
3843 if (get<SPIRType>(result_type).vecsize == 1)
3844 {
3845 if (!requires_scalar_reflect)
3846 {
3847 requires_scalar_reflect = true;
3848 force_recompile();
3849 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003850 emit_binary_func_op(result_type, id, args[0], args[1], "spvReflect");
Hans-Kristian Arntzen041f1032019-07-03 12:24:58 +02003851 }
3852 else
3853 CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count);
3854 break;
3855
3856 case GLSLstd450Refract:
3857 if (get<SPIRType>(result_type).vecsize == 1)
3858 {
3859 if (!requires_scalar_refract)
3860 {
3861 requires_scalar_refract = true;
3862 force_recompile();
3863 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003864 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "spvRefract");
Hans-Kristian Arntzen041f1032019-07-03 12:24:58 +02003865 }
3866 else
3867 CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count);
3868 break;
3869
Hans-Kristian Arntzenc7eda1b2019-07-17 11:24:31 +02003870 case GLSLstd450FaceForward:
3871 if (get<SPIRType>(result_type).vecsize == 1)
3872 {
3873 if (!requires_scalar_faceforward)
3874 {
3875 requires_scalar_faceforward = true;
3876 force_recompile();
3877 }
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01003878 emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "spvFaceForward");
Hans-Kristian Arntzenc7eda1b2019-07-17 11:24:31 +02003879 }
3880 else
3881 CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count);
3882 break;
3883
Robert Konrad8e9bf1f2016-08-18 12:40:35 +02003884 default:
3885 CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count);
3886 break;
3887 }
3888}
3889
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01003890void CompilerHLSL::read_access_chain_array(const string &lhs, const SPIRAccessChain &chain)
3891{
3892 auto &type = get<SPIRType>(chain.basetype);
3893
3894 // Need to use a reserved identifier here since it might shadow an identifier in the access chain input or other loops.
3895 auto ident = get_unique_identifier();
3896
3897 statement("[unroll]");
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01003898 statement("for (int ", ident, " = 0; ", ident, " < ", to_array_size(type, uint32_t(type.array.size() - 1)), "; ",
3899 ident, "++)");
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01003900 begin_scope();
3901 auto subchain = chain;
3902 subchain.dynamic_index = join(ident, " * ", chain.array_stride, " + ", chain.dynamic_index);
3903 subchain.basetype = type.parent_type;
3904 if (!get<SPIRType>(subchain.basetype).array.empty())
3905 subchain.array_stride = get_decoration(subchain.basetype, DecorationArrayStride);
3906 read_access_chain(nullptr, join(lhs, "[", ident, "]"), subchain);
3907 end_scope();
3908}
3909
3910void CompilerHLSL::read_access_chain_struct(const string &lhs, const SPIRAccessChain &chain)
3911{
3912 auto &type = get<SPIRType>(chain.basetype);
3913 auto subchain = chain;
3914 uint32_t member_count = uint32_t(type.member_types.size());
3915
3916 for (uint32_t i = 0; i < member_count; i++)
3917 {
3918 uint32_t offset = type_struct_member_offset(type, i);
3919 subchain.static_index = chain.static_index + offset;
3920 subchain.basetype = type.member_types[i];
3921
Hans-Kristian Arntzen1cbd71b2020-01-08 14:27:02 +01003922 subchain.matrix_stride = 0;
3923 subchain.array_stride = 0;
3924 subchain.row_major_matrix = false;
3925
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01003926 auto &member_type = get<SPIRType>(subchain.basetype);
3927 if (member_type.columns > 1)
3928 {
3929 subchain.matrix_stride = type_struct_member_matrix_stride(type, i);
3930 subchain.row_major_matrix = has_member_decoration(type.self, i, DecorationRowMajor);
3931 }
3932
3933 if (!member_type.array.empty())
3934 subchain.array_stride = type_struct_member_array_stride(type, i);
3935
3936 read_access_chain(nullptr, join(lhs, ".", to_member_name(type, i)), subchain);
3937 }
3938}
3939
3940void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIRAccessChain &chain)
Hans-Kristian Arntzen4375aa32017-08-15 10:12:08 +02003941{
3942 auto &type = get<SPIRType>(chain.basetype);
3943
3944 SPIRType target_type;
3945 target_type.basetype = SPIRType::UInt;
3946 target_type.vecsize = type.vecsize;
3947 target_type.columns = type.columns;
3948
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02003949 if (!type.array.empty())
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01003950 {
3951 read_access_chain_array(lhs, chain);
3952 return;
3953 }
3954 else if (type.basetype == SPIRType::Struct)
3955 {
3956 read_access_chain_struct(lhs, chain);
3957 return;
3958 }
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02003959 else if (type.width != 32 && !hlsl_options.enable_16bit_types)
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02003960 SPIRV_CROSS_THROW("Reading types other than 32-bit from ByteAddressBuffer not yet supported, unless SM 6.2 and "
3961 "native 16-bit types are enabled.");
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02003962
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02003963 string base = chain.base;
3964 if (has_decoration(chain.self, DecorationNonUniform))
3965 convert_non_uniform_expression(base, chain.self);
3966
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02003967 bool templated_load = hlsl_options.shader_model >= 62;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02003968 string load_expr;
3969
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02003970 string template_expr;
3971 if (templated_load)
3972 template_expr = join("<", type_to_glsl(type), ">");
3973
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02003974 // Load a vector or scalar.
3975 if (type.columns == 1 && !chain.row_major_matrix)
Hans-Kristian Arntzen4375aa32017-08-15 10:12:08 +02003976 {
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02003977 const char *load_op = nullptr;
3978 switch (type.vecsize)
3979 {
3980 case 1:
3981 load_op = "Load";
3982 break;
3983 case 2:
3984 load_op = "Load2";
3985 break;
3986 case 3:
3987 load_op = "Load3";
3988 break;
3989 case 4:
3990 load_op = "Load4";
3991 break;
3992 default:
3993 SPIRV_CROSS_THROW("Unknown vector size.");
3994 }
3995
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02003996 if (templated_load)
3997 load_op = "Load";
3998
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02003999 load_expr = join(base, ".", load_op, template_expr, "(", chain.dynamic_index, chain.static_index, ")");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004000 }
4001 else if (type.columns == 1)
4002 {
4003 // Strided load since we are loading a column from a row-major matrix.
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004004 if (templated_load)
4005 {
4006 auto scalar_type = type;
4007 scalar_type.vecsize = 1;
4008 scalar_type.columns = 1;
4009 template_expr = join("<", type_to_glsl(scalar_type), ">");
4010 if (type.vecsize > 1)
4011 load_expr += type_to_glsl(type) + "(";
4012 }
4013 else if (type.vecsize > 1)
Hans-Kristian Arntzen22e94912017-10-26 17:40:45 +02004014 {
4015 load_expr = type_to_glsl(target_type);
4016 load_expr += "(";
4017 }
4018
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004019 for (uint32_t r = 0; r < type.vecsize; r++)
4020 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004021 load_expr += join(base, ".Load", template_expr, "(", chain.dynamic_index,
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02004022 chain.static_index + r * chain.matrix_stride, ")");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004023 if (r + 1 < type.vecsize)
4024 load_expr += ", ";
4025 }
Hans-Kristian Arntzen22e94912017-10-26 17:40:45 +02004026
4027 if (type.vecsize > 1)
4028 load_expr += ")";
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004029 }
4030 else if (!chain.row_major_matrix)
4031 {
4032 // Load a matrix, column-major, the easy case.
4033 const char *load_op = nullptr;
4034 switch (type.vecsize)
4035 {
4036 case 1:
4037 load_op = "Load";
4038 break;
4039 case 2:
4040 load_op = "Load2";
4041 break;
4042 case 3:
4043 load_op = "Load3";
4044 break;
4045 case 4:
4046 load_op = "Load4";
4047 break;
4048 default:
4049 SPIRV_CROSS_THROW("Unknown vector size.");
4050 }
4051
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004052 if (templated_load)
4053 {
4054 auto vector_type = type;
4055 vector_type.columns = 1;
4056 template_expr = join("<", type_to_glsl(vector_type), ">");
4057 load_expr = type_to_glsl(type);
4058 load_op = "Load";
4059 }
4060 else
4061 {
4062 // Note, this loading style in HLSL is *actually* row-major, but we always treat matrices as transposed in this backend,
4063 // so row-major is technically column-major ...
4064 load_expr = type_to_glsl(target_type);
4065 }
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004066 load_expr += "(";
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004067
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004068 for (uint32_t c = 0; c < type.columns; c++)
4069 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004070 load_expr += join(base, ".", load_op, template_expr, "(", chain.dynamic_index,
Hans-Kristian Arntzen4a6d7542017-10-26 17:43:03 +02004071 chain.static_index + c * chain.matrix_stride, ")");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004072 if (c + 1 < type.columns)
4073 load_expr += ", ";
4074 }
4075 load_expr += ")";
4076 }
4077 else
4078 {
4079 // Pick out elements one by one ... Hopefully compilers are smart enough to recognize this pattern
4080 // considering HLSL is "row-major decl", but "column-major" memory layout (basically implicit transpose model, ugh) ...
4081
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004082 if (templated_load)
4083 {
4084 load_expr = type_to_glsl(type);
4085 auto scalar_type = type;
4086 scalar_type.vecsize = 1;
4087 scalar_type.columns = 1;
4088 template_expr = join("<", type_to_glsl(scalar_type), ">");
4089 }
4090 else
4091 load_expr = type_to_glsl(target_type);
4092
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004093 load_expr += "(";
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004094
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004095 for (uint32_t c = 0; c < type.columns; c++)
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004096 {
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004097 for (uint32_t r = 0; r < type.vecsize; r++)
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004098 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004099 load_expr += join(base, ".Load", template_expr, "(", chain.dynamic_index,
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004100 chain.static_index + c * (type.width / 8) + r * chain.matrix_stride, ")");
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004101
4102 if ((r + 1 < type.vecsize) || (c + 1 < type.columns))
4103 load_expr += ", ";
4104 }
4105 }
4106 load_expr += ")";
Hans-Kristian Arntzen4375aa32017-08-15 10:12:08 +02004107 }
4108
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004109 if (!templated_load)
4110 {
4111 auto bitcast_op = bitcast_glsl_op(type, target_type);
4112 if (!bitcast_op.empty())
4113 load_expr = join(bitcast_op, "(", load_expr, ")");
4114 }
Hans-Kristian Arntzen4375aa32017-08-15 10:12:08 +02004115
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01004116 if (lhs.empty())
4117 {
4118 assert(expr);
Daniel Thornburgh44c33332022-03-02 23:02:38 +00004119 *expr = std::move(load_expr);
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01004120 }
4121 else
4122 statement(lhs, " = ", load_expr, ";");
Hans-Kristian Arntzen4375aa32017-08-15 10:12:08 +02004123}
4124
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004125void CompilerHLSL::emit_load(const Instruction &instruction)
4126{
4127 auto ops = stream(instruction);
4128
4129 auto *chain = maybe_get<SPIRAccessChain>(ops[2]);
4130 if (chain)
4131 {
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004132 uint32_t result_type = ops[0];
4133 uint32_t id = ops[1];
4134 uint32_t ptr = ops[2];
4135
Hans-Kristian Arntzen22e94912017-10-26 17:40:45 +02004136 auto &type = get<SPIRType>(result_type);
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01004137 bool composite_load = !type.array.empty() || type.basetype == SPIRType::Struct;
Hans-Kristian Arntzen22e94912017-10-26 17:40:45 +02004138
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01004139 if (composite_load)
4140 {
4141 // We cannot make this work in one single expression as we might have nested structures and arrays,
4142 // so unroll the load to an uninitialized temporary.
4143 emit_uninitialized_temporary_expression(result_type, id);
4144 read_access_chain(nullptr, to_expression(id), *chain);
4145 track_expression_read(chain->self);
4146 }
4147 else
4148 {
4149 string load_expr;
4150 read_access_chain(&load_expr, "", *chain);
4151
4152 bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
4153
4154 // If we are forwarding this load,
4155 // don't register the read to access chain here, defer that to when we actually use the expression,
4156 // using the add_implied_read_expression mechanism.
4157 if (!forward)
4158 track_expression_read(chain->self);
4159
4160 // Do not forward complex load sequences like matrices, structs and arrays.
4161 if (type.columns > 1)
4162 forward = false;
4163
4164 auto &e = emit_op(result_type, id, load_expr, forward, true);
4165 e.need_transpose = false;
4166 register_read(id, ptr, forward);
4167 inherit_expression_dependencies(id, ptr);
4168 if (forward)
4169 add_implied_read_expression(e, chain->self);
4170 }
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004171 }
4172 else
4173 CompilerGLSL::emit_instruction(instruction);
4174}
4175
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01004176void CompilerHLSL::write_access_chain_array(const SPIRAccessChain &chain, uint32_t value,
4177 const SmallVector<uint32_t> &composite_chain)
4178{
4179 auto &type = get<SPIRType>(chain.basetype);
4180
4181 // Need to use a reserved identifier here since it might shadow an identifier in the access chain input or other loops.
4182 auto ident = get_unique_identifier();
4183
4184 uint32_t id = ir.increase_bound_by(2);
4185 uint32_t int_type_id = id + 1;
4186 SPIRType int_type;
4187 int_type.basetype = SPIRType::Int;
4188 int_type.width = 32;
4189 set<SPIRType>(int_type_id, int_type);
4190 set<SPIRExpression>(id, ident, int_type_id, true);
4191 set_name(id, ident);
4192 suppressed_usage_tracking.insert(id);
4193
4194 statement("[unroll]");
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01004195 statement("for (int ", ident, " = 0; ", ident, " < ", to_array_size(type, uint32_t(type.array.size() - 1)), "; ",
4196 ident, "++)");
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01004197 begin_scope();
4198 auto subchain = chain;
4199 subchain.dynamic_index = join(ident, " * ", chain.array_stride, " + ", chain.dynamic_index);
4200 subchain.basetype = type.parent_type;
4201
4202 // Forcefully allow us to use an ID here by setting MSB.
4203 auto subcomposite_chain = composite_chain;
4204 subcomposite_chain.push_back(0x80000000u | id);
4205
4206 if (!get<SPIRType>(subchain.basetype).array.empty())
4207 subchain.array_stride = get_decoration(subchain.basetype, DecorationArrayStride);
4208
4209 write_access_chain(subchain, value, subcomposite_chain);
4210 end_scope();
4211}
4212
4213void CompilerHLSL::write_access_chain_struct(const SPIRAccessChain &chain, uint32_t value,
4214 const SmallVector<uint32_t> &composite_chain)
4215{
4216 auto &type = get<SPIRType>(chain.basetype);
4217 uint32_t member_count = uint32_t(type.member_types.size());
4218 auto subchain = chain;
4219
4220 auto subcomposite_chain = composite_chain;
4221 subcomposite_chain.push_back(0);
4222
4223 for (uint32_t i = 0; i < member_count; i++)
4224 {
4225 uint32_t offset = type_struct_member_offset(type, i);
4226 subchain.static_index = chain.static_index + offset;
4227 subchain.basetype = type.member_types[i];
4228
Hans-Kristian Arntzen1cbd71b2020-01-08 14:27:02 +01004229 subchain.matrix_stride = 0;
4230 subchain.array_stride = 0;
4231 subchain.row_major_matrix = false;
4232
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01004233 auto &member_type = get<SPIRType>(subchain.basetype);
4234 if (member_type.columns > 1)
4235 {
4236 subchain.matrix_stride = type_struct_member_matrix_stride(type, i);
4237 subchain.row_major_matrix = has_member_decoration(type.self, i, DecorationRowMajor);
4238 }
4239
4240 if (!member_type.array.empty())
4241 subchain.array_stride = type_struct_member_array_stride(type, i);
4242
4243 subcomposite_chain.back() = i;
4244 write_access_chain(subchain, value, subcomposite_chain);
4245 }
4246}
4247
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01004248string CompilerHLSL::write_access_chain_value(uint32_t value, const SmallVector<uint32_t> &composite_chain,
4249 bool enclose)
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01004250{
4251 string ret;
4252 if (composite_chain.empty())
4253 ret = to_expression(value);
4254 else
4255 {
4256 AccessChainMeta meta;
4257 ret = access_chain_internal(value, composite_chain.data(), uint32_t(composite_chain.size()),
4258 ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_LITERAL_MSB_FORCE_ID, &meta);
4259 }
4260
4261 if (enclose)
4262 ret = enclose_expression(ret);
4263 return ret;
4264}
4265
4266void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t value,
4267 const SmallVector<uint32_t> &composite_chain)
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004268{
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004269 auto &type = get<SPIRType>(chain.basetype);
4270
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004271 // Make sure we trigger a read of the constituents in the access chain.
4272 track_expression_read(chain.self);
4273
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004274 SPIRType target_type;
4275 target_type.basetype = SPIRType::UInt;
4276 target_type.vecsize = type.vecsize;
4277 target_type.columns = type.columns;
4278
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004279 if (!type.array.empty())
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01004280 {
4281 write_access_chain_array(chain, value, composite_chain);
4282 register_write(chain.self);
4283 return;
4284 }
4285 else if (type.basetype == SPIRType::Struct)
4286 {
4287 write_access_chain_struct(chain, value, composite_chain);
4288 register_write(chain.self);
4289 return;
4290 }
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004291 else if (type.width != 32 && !hlsl_options.enable_16bit_types)
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02004292 SPIRV_CROSS_THROW("Writing types other than 32-bit to RWByteAddressBuffer not yet supported, unless SM 6.2 and "
4293 "native 16-bit types are enabled.");
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004294
4295 bool templated_store = hlsl_options.shader_model >= 62;
4296
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004297 auto base = chain.base;
4298 if (has_decoration(chain.self, DecorationNonUniform))
4299 convert_non_uniform_expression(base, chain.self);
4300
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004301 string template_expr;
4302 if (templated_store)
4303 template_expr = join("<", type_to_glsl(type), ">");
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004304
4305 if (type.columns == 1 && !chain.row_major_matrix)
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004306 {
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004307 const char *store_op = nullptr;
4308 switch (type.vecsize)
4309 {
4310 case 1:
4311 store_op = "Store";
4312 break;
4313 case 2:
4314 store_op = "Store2";
4315 break;
4316 case 3:
4317 store_op = "Store3";
4318 break;
4319 case 4:
4320 store_op = "Store4";
4321 break;
4322 default:
4323 SPIRV_CROSS_THROW("Unknown vector size.");
4324 }
4325
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01004326 auto store_expr = write_access_chain_value(value, composite_chain, false);
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004327
4328 if (!templated_store)
4329 {
4330 auto bitcast_op = bitcast_glsl_op(target_type, type);
4331 if (!bitcast_op.empty())
4332 store_expr = join(bitcast_op, "(", store_expr, ")");
4333 }
4334 else
4335 store_op = "Store";
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004336 statement(base, ".", store_op, template_expr, "(", chain.dynamic_index, chain.static_index, ", ",
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02004337 store_expr, ");");
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004338 }
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004339 else if (type.columns == 1)
4340 {
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004341 if (templated_store)
4342 {
4343 auto scalar_type = type;
4344 scalar_type.vecsize = 1;
4345 scalar_type.columns = 1;
4346 template_expr = join("<", type_to_glsl(scalar_type), ">");
4347 }
4348
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004349 // Strided store.
4350 for (uint32_t r = 0; r < type.vecsize; r++)
4351 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01004352 auto store_expr = write_access_chain_value(value, composite_chain, true);
Hans-Kristian Arntzen22e94912017-10-26 17:40:45 +02004353 if (type.vecsize > 1)
4354 {
4355 store_expr += ".";
4356 store_expr += index_to_swizzle(r);
4357 }
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004358 remove_duplicate_swizzle(store_expr);
Hans-Kristian Arntzen22e94912017-10-26 17:40:45 +02004359
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004360 if (!templated_store)
4361 {
4362 auto bitcast_op = bitcast_glsl_op(target_type, type);
4363 if (!bitcast_op.empty())
4364 store_expr = join(bitcast_op, "(", store_expr, ")");
4365 }
4366
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004367 statement(base, ".Store", template_expr, "(", chain.dynamic_index,
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02004368 chain.static_index + chain.matrix_stride * r, ", ", store_expr, ");");
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004369 }
4370 }
4371 else if (!chain.row_major_matrix)
4372 {
4373 const char *store_op = nullptr;
4374 switch (type.vecsize)
4375 {
4376 case 1:
4377 store_op = "Store";
4378 break;
4379 case 2:
4380 store_op = "Store2";
4381 break;
4382 case 3:
4383 store_op = "Store3";
4384 break;
4385 case 4:
4386 store_op = "Store4";
4387 break;
4388 default:
4389 SPIRV_CROSS_THROW("Unknown vector size.");
4390 }
4391
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004392 if (templated_store)
4393 {
4394 store_op = "Store";
4395 auto vector_type = type;
4396 vector_type.columns = 1;
4397 template_expr = join("<", type_to_glsl(vector_type), ">");
4398 }
4399
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004400 for (uint32_t c = 0; c < type.columns; c++)
4401 {
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01004402 auto store_expr = join(write_access_chain_value(value, composite_chain, true), "[", c, "]");
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004403
4404 if (!templated_store)
4405 {
4406 auto bitcast_op = bitcast_glsl_op(target_type, type);
4407 if (!bitcast_op.empty())
4408 store_expr = join(bitcast_op, "(", store_expr, ")");
4409 }
4410
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004411 statement(base, ".", store_op, template_expr, "(", chain.dynamic_index,
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02004412 chain.static_index + c * chain.matrix_stride, ", ", store_expr, ");");
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004413 }
4414 }
4415 else
4416 {
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02004417 if (templated_store)
4418 {
4419 auto scalar_type = type;
4420 scalar_type.vecsize = 1;
4421 scalar_type.columns = 1;
4422 template_expr = join("<", type_to_glsl(scalar_type), ">");
4423 }
4424
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004425 for (uint32_t r = 0; r < type.vecsize; r++)
4426 {
4427 for (uint32_t c = 0; c < type.columns; c++)
4428 {
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01004429 auto store_expr =
4430 join(write_access_chain_value(value, composite_chain, true), "[", c, "].", index_to_swizzle(r));
Hans-Kristian Arntzen4590c632018-01-04 13:16:56 +01004431 remove_duplicate_swizzle(store_expr);
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004432 auto bitcast_op = bitcast_glsl_op(target_type, type);
4433 if (!bitcast_op.empty())
4434 store_expr = join(bitcast_op, "(", store_expr, ")");
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004435 statement(base, ".Store", template_expr, "(", chain.dynamic_index,
Hans-Kristian Arntzenafce0302017-10-26 17:16:32 +02004436 chain.static_index + c * (type.width / 8) + r * chain.matrix_stride, ", ", store_expr, ");");
4437 }
4438 }
4439 }
4440
4441 register_write(chain.self);
4442}
4443
4444void CompilerHLSL::emit_store(const Instruction &instruction)
4445{
4446 auto ops = stream(instruction);
4447 auto *chain = maybe_get<SPIRAccessChain>(ops[0]);
4448 if (chain)
Hans-Kristian Arntzen151ff1e2020-01-08 14:17:28 +01004449 write_access_chain(*chain, ops[1], {});
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004450 else
4451 CompilerGLSL::emit_instruction(instruction);
4452}
4453
4454void CompilerHLSL::emit_access_chain(const Instruction &instruction)
4455{
4456 auto ops = stream(instruction);
4457 uint32_t length = instruction.length;
4458
4459 bool need_byte_access_chain = false;
4460 auto &type = expression_type(ops[2]);
Hans-Kristian Arntzen4e7777c2019-01-30 13:31:17 +01004461 const auto *chain = maybe_get<SPIRAccessChain>(ops[2]);
4462
4463 if (chain)
4464 {
4465 // Keep tacking on an existing access chain.
4466 need_byte_access_chain = true;
4467 }
4468 else if (type.storage == StorageClassStorageBuffer || has_decoration(type.self, DecorationBufferBlock))
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004469 {
4470 // If we are starting to poke into an SSBO, we are dealing with ByteAddressBuffers, and we need
4471 // to emit SPIRAccessChain rather than a plain SPIRExpression.
4472 uint32_t chain_arguments = length - 3;
4473 if (chain_arguments > type.array.size())
4474 need_byte_access_chain = true;
4475 }
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004476
4477 if (need_byte_access_chain)
4478 {
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01004479 // If we have a chain variable, we are already inside the SSBO, and any array type will refer to arrays within a block,
4480 // and not array of SSBO.
4481 uint32_t to_plain_buffer_length = chain ? 0u : static_cast<uint32_t>(type.array.size());
4482
Hans-Kristian Arntzen18b82ca2018-07-09 14:02:50 +02004483 auto *backing_variable = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004484
4485 string base;
4486 if (to_plain_buffer_length != 0)
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01004487 base = access_chain(ops[2], &ops[3], to_plain_buffer_length, get<SPIRType>(ops[0]));
Hans-Kristian Arntzenaf672b72018-09-10 10:21:08 +02004488 else if (chain)
4489 base = chain->base;
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004490 else
4491 base = to_expression(ops[2]);
4492
Hans-Kristian Arntzen4375aa32017-08-15 10:12:08 +02004493 // Start traversing type hierarchy at the proper non-pointer types.
Chip Davisfc02b3d2019-01-08 12:54:40 -06004494 auto *basetype = &get_pointee_type(type);
Hans-Kristian Arntzen4375aa32017-08-15 10:12:08 +02004495
4496 // Traverse the type hierarchy down to the actual buffer types.
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004497 for (uint32_t i = 0; i < to_plain_buffer_length; i++)
Hans-Kristian Arntzen4375aa32017-08-15 10:12:08 +02004498 {
4499 assert(basetype->parent_type);
4500 basetype = &get<SPIRType>(basetype->parent_type);
4501 }
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004502
4503 uint32_t matrix_stride = 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01004504 uint32_t array_stride = 0;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004505 bool row_major_matrix = false;
4506
4507 // Inherit matrix information.
4508 if (chain)
4509 {
4510 matrix_stride = chain->matrix_stride;
4511 row_major_matrix = chain->row_major_matrix;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01004512 array_stride = chain->array_stride;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004513 }
4514
Hans-Kristian Arntzenc2565252020-01-08 14:27:34 +01004515 auto offsets = flattened_access_chain_offset(*basetype, &ops[3 + to_plain_buffer_length],
4516 length - 3 - to_plain_buffer_length, 0, 1, &row_major_matrix,
4517 &matrix_stride, &array_stride);
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004518
4519 auto &e = set<SPIRAccessChain>(ops[1], ops[0], type.storage, base, offsets.first, offsets.second);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004520 e.row_major_matrix = row_major_matrix;
4521 e.matrix_stride = matrix_stride;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01004522 e.array_stride = array_stride;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004523 e.immutable = should_forward(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02004524 e.loaded_from = backing_variable ? backing_variable->self : ID(0);
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02004525
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004526 if (chain)
4527 {
4528 e.dynamic_index += chain->dynamic_index;
4529 e.static_index += chain->static_index;
4530 }
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01004531
4532 for (uint32_t i = 2; i < length; i++)
4533 {
4534 inherit_expression_dependencies(ops[1], ops[i]);
4535 add_implied_read_expression(e, ops[i]);
4536 }
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004537 }
4538 else
4539 {
4540 CompilerGLSL::emit_instruction(instruction);
4541 }
4542}
4543
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02004544void CompilerHLSL::emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op)
4545{
4546 const char *atomic_op = nullptr;
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +02004547
4548 string value_expr;
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004549 if (op != OpAtomicIDecrement && op != OpAtomicIIncrement && op != OpAtomicLoad && op != OpAtomicStore)
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +02004550 value_expr = to_expression(ops[op == OpAtomicCompareExchange ? 6 : 5]);
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +02004551
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004552 bool is_atomic_store = false;
4553
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02004554 switch (op)
4555 {
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +02004556 case OpAtomicIIncrement:
4557 atomic_op = "InterlockedAdd";
4558 value_expr = "1";
4559 break;
4560
4561 case OpAtomicIDecrement:
4562 atomic_op = "InterlockedAdd";
4563 value_expr = "-1";
4564 break;
4565
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004566 case OpAtomicLoad:
4567 atomic_op = "InterlockedAdd";
4568 value_expr = "0";
4569 break;
4570
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02004571 case OpAtomicISub:
4572 atomic_op = "InterlockedAdd";
4573 value_expr = join("-", enclose_expression(value_expr));
4574 break;
4575
4576 case OpAtomicSMin:
4577 case OpAtomicUMin:
4578 atomic_op = "InterlockedMin";
4579 break;
4580
4581 case OpAtomicSMax:
4582 case OpAtomicUMax:
4583 atomic_op = "InterlockedMax";
4584 break;
4585
4586 case OpAtomicAnd:
4587 atomic_op = "InterlockedAnd";
4588 break;
4589
4590 case OpAtomicOr:
4591 atomic_op = "InterlockedOr";
4592 break;
4593
4594 case OpAtomicXor:
4595 atomic_op = "InterlockedXor";
4596 break;
4597
4598 case OpAtomicIAdd:
4599 atomic_op = "InterlockedAdd";
4600 break;
4601
4602 case OpAtomicExchange:
4603 atomic_op = "InterlockedExchange";
4604 break;
4605
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004606 case OpAtomicStore:
4607 atomic_op = "InterlockedExchange";
4608 is_atomic_store = true;
4609 break;
4610
Hans-Kristian Arntzen85eb9722017-10-20 15:43:45 +02004611 case OpAtomicCompareExchange:
4612 if (length < 8)
4613 SPIRV_CROSS_THROW("Not enough data for opcode.");
4614 atomic_op = "InterlockedCompareExchange";
4615 value_expr = join(to_expression(ops[7]), ", ", value_expr);
4616 break;
4617
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02004618 default:
4619 SPIRV_CROSS_THROW("Unknown atomic opcode.");
4620 }
4621
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004622 if (is_atomic_store)
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02004623 {
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004624 auto &data_type = expression_type(ops[0]);
4625 auto *chain = maybe_get<SPIRAccessChain>(ops[0]);
4626
4627 auto &tmp_id = extra_sub_expressions[ops[0]];
4628 if (!tmp_id)
4629 {
4630 tmp_id = ir.increase_bound_by(1);
4631 emit_uninitialized_temporary_expression(get_pointee_type(data_type).self, tmp_id);
4632 }
4633
4634 if (data_type.storage == StorageClassImage || !chain)
4635 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004636 statement(atomic_op, "(", to_non_uniform_aware_expression(ops[0]), ", ",
4637 to_expression(ops[3]), ", ", to_expression(tmp_id), ");");
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004638 }
4639 else
4640 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004641 string base = chain->base;
4642 if (has_decoration(chain->self, DecorationNonUniform))
4643 convert_non_uniform_expression(base, chain->self);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004644 // RWByteAddress buffer is always uint in its underlying type.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004645 statement(base, ".", atomic_op, "(", chain->dynamic_index, chain->static_index, ", ",
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02004646 to_expression(ops[3]), ", ", to_expression(tmp_id), ");");
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004647 }
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02004648 }
4649 else
4650 {
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004651 uint32_t result_type = ops[0];
4652 uint32_t id = ops[1];
4653 forced_temporaries.insert(ops[1]);
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02004654
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004655 auto &type = get<SPIRType>(result_type);
4656 statement(variable_decl(type, to_name(id)), ";");
4657
4658 auto &data_type = expression_type(ops[2]);
4659 auto *chain = maybe_get<SPIRAccessChain>(ops[2]);
4660 SPIRType::BaseType expr_type;
4661 if (data_type.storage == StorageClassImage || !chain)
4662 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004663 statement(atomic_op, "(", to_non_uniform_aware_expression(ops[2]), ", ", value_expr, ", ", to_name(id), ");");
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004664 expr_type = data_type.basetype;
4665 }
4666 else
4667 {
4668 // RWByteAddress buffer is always uint in its underlying type.
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004669 string base = chain->base;
4670 if (has_decoration(chain->self, DecorationNonUniform))
4671 convert_non_uniform_expression(base, chain->self);
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004672 expr_type = SPIRType::UInt;
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02004673 statement(base, ".", atomic_op, "(", chain->dynamic_index, chain->static_index, ", ", value_expr,
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02004674 ", ", to_name(id), ");");
4675 }
4676
4677 auto expr = bitcast_expression(type, expr_type, to_name(id));
4678 set<SPIRExpression>(id, expr, result_type, true);
4679 }
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02004680 flush_all_atomic_capable_variables();
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02004681}
4682
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004683void CompilerHLSL::emit_subgroup_op(const Instruction &i)
4684{
4685 if (hlsl_options.shader_model < 60)
4686 SPIRV_CROSS_THROW("Wave ops requires SM 6.0 or higher.");
4687
4688 const uint32_t *ops = stream(i);
4689 auto op = static_cast<Op>(i.op);
4690
4691 uint32_t result_type = ops[0];
4692 uint32_t id = ops[1];
4693
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02004694 auto scope = static_cast<Scope>(evaluate_constant_u32(ops[2]));
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004695 if (scope != ScopeSubgroup)
4696 SPIRV_CROSS_THROW("Only subgroup scope is supported.");
4697
4698 const auto make_inclusive_Sum = [&](const string &expr) -> string {
4699 return join(expr, " + ", to_expression(ops[4]));
4700 };
4701
4702 const auto make_inclusive_Product = [&](const string &expr) -> string {
4703 return join(expr, " * ", to_expression(ops[4]));
4704 };
4705
Hans-Kristian Arntzen88ddeec2020-01-09 12:10:59 +01004706 // If we need to do implicit bitcasts, make sure we do it with the correct type.
4707 uint32_t integer_width = get_integer_width_for_instruction(i);
4708 auto int_type = to_signed_basetype(integer_width);
4709 auto uint_type = to_unsigned_basetype(integer_width);
4710
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004711#define make_inclusive_BitAnd(expr) ""
4712#define make_inclusive_BitOr(expr) ""
4713#define make_inclusive_BitXor(expr) ""
4714#define make_inclusive_Min(expr) ""
4715#define make_inclusive_Max(expr) ""
4716
4717 switch (op)
4718 {
4719 case OpGroupNonUniformElect:
4720 emit_op(result_type, id, "WaveIsFirstLane()", true);
4721 break;
4722
4723 case OpGroupNonUniformBroadcast:
4724 emit_binary_func_op(result_type, id, ops[3], ops[4], "WaveReadLaneAt");
4725 break;
4726
4727 case OpGroupNonUniformBroadcastFirst:
4728 emit_unary_func_op(result_type, id, ops[3], "WaveReadLaneFirst");
4729 break;
4730
4731 case OpGroupNonUniformBallot:
4732 emit_unary_func_op(result_type, id, ops[3], "WaveActiveBallot");
4733 break;
4734
4735 case OpGroupNonUniformInverseBallot:
4736 SPIRV_CROSS_THROW("Cannot trivially implement InverseBallot in HLSL.");
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004737
4738 case OpGroupNonUniformBallotBitExtract:
4739 SPIRV_CROSS_THROW("Cannot trivially implement BallotBitExtract in HLSL.");
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004740
4741 case OpGroupNonUniformBallotFindLSB:
4742 SPIRV_CROSS_THROW("Cannot trivially implement BallotFindLSB in HLSL.");
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004743
4744 case OpGroupNonUniformBallotFindMSB:
4745 SPIRV_CROSS_THROW("Cannot trivially implement BallotFindMSB in HLSL.");
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004746
4747 case OpGroupNonUniformBallotBitCount:
4748 {
4749 auto operation = static_cast<GroupOperation>(ops[3]);
Pedro J. Estébanez1fe470b2022-07-20 22:00:35 +02004750 bool forward = should_forward(ops[4]);
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004751 if (operation == GroupOperationReduce)
4752 {
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02004753 auto left = join("countbits(", to_enclosed_expression(ops[4]), ".x) + countbits(",
4754 to_enclosed_expression(ops[4]), ".y)");
4755 auto right = join("countbits(", to_enclosed_expression(ops[4]), ".z) + countbits(",
4756 to_enclosed_expression(ops[4]), ".w)");
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004757 emit_op(result_type, id, join(left, " + ", right), forward);
4758 inherit_expression_dependencies(id, ops[4]);
4759 }
4760 else if (operation == GroupOperationInclusiveScan)
Pedro J. Estébanez1fe470b2022-07-20 22:00:35 +02004761 {
4762 auto left = join("countbits(", to_enclosed_expression(ops[4]), ".x & gl_SubgroupLeMask.x) + countbits(",
4763 to_enclosed_expression(ops[4]), ".y & gl_SubgroupLeMask.y)");
4764 auto right = join("countbits(", to_enclosed_expression(ops[4]), ".z & gl_SubgroupLeMask.z) + countbits(",
4765 to_enclosed_expression(ops[4]), ".w & gl_SubgroupLeMask.w)");
4766 emit_op(result_type, id, join(left, " + ", right), forward);
4767 if (!active_input_builtins.get(BuiltInSubgroupLeMask))
4768 {
4769 active_input_builtins.set(BuiltInSubgroupLeMask);
4770 force_recompile_guarantee_forward_progress();
4771 }
4772 }
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004773 else if (operation == GroupOperationExclusiveScan)
Pedro J. Estébanez1fe470b2022-07-20 22:00:35 +02004774 {
4775 auto left = join("countbits(", to_enclosed_expression(ops[4]), ".x & gl_SubgroupLtMask.x) + countbits(",
4776 to_enclosed_expression(ops[4]), ".y & gl_SubgroupLtMask.y)");
4777 auto right = join("countbits(", to_enclosed_expression(ops[4]), ".z & gl_SubgroupLtMask.z) + countbits(",
4778 to_enclosed_expression(ops[4]), ".w & gl_SubgroupLtMask.w)");
4779 emit_op(result_type, id, join(left, " + ", right), forward);
4780 if (!active_input_builtins.get(BuiltInSubgroupLtMask))
4781 {
4782 active_input_builtins.set(BuiltInSubgroupLtMask);
4783 force_recompile_guarantee_forward_progress();
4784 }
4785 }
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004786 else
4787 SPIRV_CROSS_THROW("Invalid BitCount operation.");
4788 break;
4789 }
4790
4791 case OpGroupNonUniformShuffle:
Hans-Kristian Arntzen0e963c62021-04-23 13:03:35 +02004792 emit_binary_func_op(result_type, id, ops[3], ops[4], "WaveReadLaneAt");
4793 break;
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004794 case OpGroupNonUniformShuffleXor:
Hans-Kristian Arntzen0e963c62021-04-23 13:03:35 +02004795 {
4796 bool forward = should_forward(ops[3]);
4797 emit_op(ops[0], ops[1],
4798 join("WaveReadLaneAt(", to_unpacked_expression(ops[3]), ", ",
4799 "WaveGetLaneIndex() ^ ", to_enclosed_expression(ops[4]), ")"), forward);
4800 inherit_expression_dependencies(ops[1], ops[3]);
4801 break;
4802 }
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004803 case OpGroupNonUniformShuffleUp:
Hans-Kristian Arntzen0e963c62021-04-23 13:03:35 +02004804 {
4805 bool forward = should_forward(ops[3]);
4806 emit_op(ops[0], ops[1],
4807 join("WaveReadLaneAt(", to_unpacked_expression(ops[3]), ", ",
4808 "WaveGetLaneIndex() - ", to_enclosed_expression(ops[4]), ")"), forward);
4809 inherit_expression_dependencies(ops[1], ops[3]);
4810 break;
4811 }
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004812 case OpGroupNonUniformShuffleDown:
Hans-Kristian Arntzen0e963c62021-04-23 13:03:35 +02004813 {
4814 bool forward = should_forward(ops[3]);
4815 emit_op(ops[0], ops[1],
4816 join("WaveReadLaneAt(", to_unpacked_expression(ops[3]), ", ",
4817 "WaveGetLaneIndex() + ", to_enclosed_expression(ops[4]), ")"), forward);
4818 inherit_expression_dependencies(ops[1], ops[3]);
4819 break;
4820 }
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004821
4822 case OpGroupNonUniformAll:
4823 emit_unary_func_op(result_type, id, ops[3], "WaveActiveAllTrue");
4824 break;
4825
4826 case OpGroupNonUniformAny:
4827 emit_unary_func_op(result_type, id, ops[3], "WaveActiveAnyTrue");
4828 break;
4829
4830 case OpGroupNonUniformAllEqual:
Hans-Kristian Arntzend6c2c1b2021-03-08 12:52:03 +01004831 emit_unary_func_op(result_type, id, ops[3], "WaveActiveAllEqual");
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004832 break;
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004833
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02004834 // clang-format off
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004835#define HLSL_GROUP_OP(op, hlsl_op, supports_scan) \
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004836case OpGroupNonUniform##op: \
4837 { \
4838 auto operation = static_cast<GroupOperation>(ops[3]); \
4839 if (operation == GroupOperationReduce) \
4840 emit_unary_func_op(result_type, id, ops[4], "WaveActive" #hlsl_op); \
4841 else if (operation == GroupOperationInclusiveScan && supports_scan) \
4842 { \
4843 bool forward = should_forward(ops[4]); \
4844 emit_op(result_type, id, make_inclusive_##hlsl_op (join("WavePrefix" #hlsl_op, "(", to_expression(ops[4]), ")")), forward); \
4845 inherit_expression_dependencies(id, ops[4]); \
4846 } \
4847 else if (operation == GroupOperationExclusiveScan && supports_scan) \
4848 emit_unary_func_op(result_type, id, ops[4], "WavePrefix" #hlsl_op); \
4849 else if (operation == GroupOperationClusteredReduce) \
4850 SPIRV_CROSS_THROW("Cannot trivially implement ClusteredReduce in HLSL."); \
4851 else \
4852 SPIRV_CROSS_THROW("Invalid group operation."); \
4853 break; \
4854 }
Hans-Kristian Arntzen88ddeec2020-01-09 12:10:59 +01004855
4856#define HLSL_GROUP_OP_CAST(op, hlsl_op, type) \
4857case OpGroupNonUniform##op: \
4858 { \
4859 auto operation = static_cast<GroupOperation>(ops[3]); \
4860 if (operation == GroupOperationReduce) \
4861 emit_unary_func_op_cast(result_type, id, ops[4], "WaveActive" #hlsl_op, type, type); \
4862 else \
4863 SPIRV_CROSS_THROW("Invalid group operation."); \
4864 break; \
4865 }
4866
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004867 HLSL_GROUP_OP(FAdd, Sum, true)
4868 HLSL_GROUP_OP(FMul, Product, true)
4869 HLSL_GROUP_OP(FMin, Min, false)
4870 HLSL_GROUP_OP(FMax, Max, false)
4871 HLSL_GROUP_OP(IAdd, Sum, true)
4872 HLSL_GROUP_OP(IMul, Product, true)
Hans-Kristian Arntzen88ddeec2020-01-09 12:10:59 +01004873 HLSL_GROUP_OP_CAST(SMin, Min, int_type)
4874 HLSL_GROUP_OP_CAST(SMax, Max, int_type)
4875 HLSL_GROUP_OP_CAST(UMin, Min, uint_type)
4876 HLSL_GROUP_OP_CAST(UMax, Max, uint_type)
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004877 HLSL_GROUP_OP(BitwiseAnd, BitAnd, false)
4878 HLSL_GROUP_OP(BitwiseOr, BitOr, false)
4879 HLSL_GROUP_OP(BitwiseXor, BitXor, false)
Hans-Kristian Arntzend6c2c1b2021-03-08 12:52:03 +01004880 HLSL_GROUP_OP_CAST(LogicalAnd, BitAnd, uint_type)
4881 HLSL_GROUP_OP_CAST(LogicalOr, BitOr, uint_type)
4882 HLSL_GROUP_OP_CAST(LogicalXor, BitXor, uint_type)
Hans-Kristian Arntzen88ddeec2020-01-09 12:10:59 +01004883
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004884#undef HLSL_GROUP_OP
Hans-Kristian Arntzen88ddeec2020-01-09 12:10:59 +01004885#undef HLSL_GROUP_OP_CAST
Hans-Kristian Arntzenb9cd3dc2018-04-17 15:01:31 +02004886 // clang-format on
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004887
4888 case OpGroupNonUniformQuadSwap:
4889 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02004890 uint32_t direction = evaluate_constant_u32(ops[4]);
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02004891 if (direction == 0)
4892 emit_unary_func_op(result_type, id, ops[3], "QuadReadAcrossX");
4893 else if (direction == 1)
4894 emit_unary_func_op(result_type, id, ops[3], "QuadReadAcrossY");
4895 else if (direction == 2)
4896 emit_unary_func_op(result_type, id, ops[3], "QuadReadAcrossDiagonal");
4897 else
4898 SPIRV_CROSS_THROW("Invalid quad swap direction.");
4899 break;
4900 }
4901
4902 case OpGroupNonUniformQuadBroadcast:
4903 {
4904 emit_binary_func_op(result_type, id, ops[3], ops[4], "QuadReadLaneAt");
4905 break;
4906 }
4907
4908 default:
4909 SPIRV_CROSS_THROW("Invalid opcode for subgroup.");
4910 }
4911
4912 register_control_dependent_expression(id);
4913}
4914
Robert Konradda5f99b2016-08-14 23:54:51 +02004915void CompilerHLSL::emit_instruction(const Instruction &instruction)
4916{
4917 auto ops = stream(instruction);
4918 auto opcode = static_cast<Op>(instruction.op);
Robert Konradda5f99b2016-08-14 23:54:51 +02004919
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004920#define HLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
4921#define HLSL_BOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004922 emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004923#define HLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
4924#define HLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
4925#define HLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
4926#define HLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
4927#define HLSL_BFOP_CAST(op, type) \
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004928 emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02004929#define HLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
4930#define HLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
Robert Konradda5f99b2016-08-14 23:54:51 +02004931
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004932 // If we need to do implicit bitcasts, make sure we do it with the correct type.
4933 uint32_t integer_width = get_integer_width_for_instruction(instruction);
4934 auto int_type = to_signed_basetype(integer_width);
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02004935 auto uint_type = to_unsigned_basetype(integer_width);
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01004936
Hans-Kristian Arntzen31be74a2022-03-03 11:04:45 +01004937 opcode = get_remapped_spirv_op(opcode);
4938
Robert Konradda5f99b2016-08-14 23:54:51 +02004939 switch (opcode)
4940 {
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02004941 case OpAccessChain:
4942 case OpInBoundsAccessChain:
4943 {
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004944 emit_access_chain(instruction);
4945 break;
4946 }
Asuka55dfbea2020-04-17 22:46:06 +08004947 case OpBitcast:
4948 {
4949 auto bitcast_type = get_bitcast_type(ops[0], ops[2]);
4950 if (bitcast_type == CompilerHLSL::TypeNormal)
4951 CompilerGLSL::emit_instruction(instruction);
4952 else
4953 {
4954 if (!requires_uint2_packing)
4955 {
4956 requires_uint2_packing = true;
4957 force_recompile();
4958 }
4959
4960 if (bitcast_type == CompilerHLSL::TypePackUint2x32)
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004961 emit_unary_func_op(ops[0], ops[1], ops[2], "spvPackUint2x32");
Asuka55dfbea2020-04-17 22:46:06 +08004962 else
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01004963 emit_unary_func_op(ops[0], ops[1], ops[2], "spvUnpackUint2x32");
Asuka55dfbea2020-04-17 22:46:06 +08004964 }
4965
4966 break;
4967 }
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02004968
Hans-Kristian Arntzen8216e872021-06-28 11:10:55 +02004969 case OpSelect:
4970 {
4971 auto &value_type = expression_type(ops[3]);
4972 if (value_type.basetype == SPIRType::Struct || is_array(value_type))
4973 {
4974 // HLSL does not support ternary expressions on composites.
4975 // Cannot use branches, since we might be in a continue block
4976 // where explicit control flow is prohibited.
4977 // Emit a helper function where we can use control flow.
4978 TypeID value_type_id = expression_type_id(ops[3]);
4979 auto itr = std::find(composite_selection_workaround_types.begin(),
4980 composite_selection_workaround_types.end(),
4981 value_type_id);
4982 if (itr == composite_selection_workaround_types.end())
4983 {
4984 composite_selection_workaround_types.push_back(value_type_id);
4985 force_recompile();
4986 }
4987 emit_uninitialized_temporary_expression(ops[0], ops[1]);
4988 statement("spvSelectComposite(",
4989 to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
4990 to_expression(ops[3]), ", ", to_expression(ops[4]), ");");
4991 }
4992 else
4993 CompilerGLSL::emit_instruction(instruction);
4994 break;
4995 }
4996
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02004997 case OpStore:
4998 {
4999 emit_store(instruction);
5000 break;
5001 }
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02005002
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02005003 case OpLoad:
5004 {
5005 emit_load(instruction);
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02005006 break;
5007 }
5008
Robert Konradda5f99b2016-08-14 23:54:51 +02005009 case OpMatrixTimesVector:
5010 {
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +02005011 // Matrices are kept in a transposed state all the time, flip multiplication order always.
Robert Konrad2da32f72017-01-27 16:51:50 +01005012 emit_binary_func_op(ops[0], ops[1], ops[3], ops[2], "mul");
Robert Konradda5f99b2016-08-14 23:54:51 +02005013 break;
5014 }
Robert Konrade7b02582017-03-24 13:58:39 +01005015
Robert Konrad7534b222016-08-18 11:45:50 +02005016 case OpVectorTimesMatrix:
5017 {
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +02005018 // Matrices are kept in a transposed state all the time, flip multiplication order always.
Robert Konrad2da32f72017-01-27 16:51:50 +01005019 emit_binary_func_op(ops[0], ops[1], ops[3], ops[2], "mul");
Robert Konrad7534b222016-08-18 11:45:50 +02005020 break;
5021 }
Robert Konrade7b02582017-03-24 13:58:39 +01005022
Robert Konrad7534b222016-08-18 11:45:50 +02005023 case OpMatrixTimesMatrix:
5024 {
Hans-Kristian Arntzen47a18b92019-07-23 10:56:57 +02005025 // Matrices are kept in a transposed state all the time, flip multiplication order always.
Robert Konrad2da32f72017-01-27 16:51:50 +01005026 emit_binary_func_op(ops[0], ops[1], ops[3], ops[2], "mul");
Robert Konrad7534b222016-08-18 11:45:50 +02005027 break;
5028 }
Robert Konrade7b02582017-03-24 13:58:39 +01005029
Hans-Kristian Arntzenf8b084d2019-07-01 10:57:27 +02005030 case OpOuterProduct:
5031 {
5032 uint32_t result_type = ops[0];
5033 uint32_t id = ops[1];
5034 uint32_t a = ops[2];
5035 uint32_t b = ops[3];
5036
5037 auto &type = get<SPIRType>(result_type);
5038 string expr = type_to_glsl_constructor(type);
5039 expr += "(";
5040 for (uint32_t col = 0; col < type.columns; col++)
5041 {
5042 expr += to_enclosed_expression(a);
5043 expr += " * ";
5044 expr += to_extract_component_expression(b, col);
5045 if (col + 1 < type.columns)
5046 expr += ", ";
5047 }
5048 expr += ")";
5049 emit_op(result_type, id, expr, should_forward(a) && should_forward(b));
5050 inherit_expression_dependencies(id, a);
5051 inherit_expression_dependencies(id, b);
5052 break;
5053 }
5054
Robert Konrad1a48d7d2016-08-18 12:54:22 +02005055 case OpFMod:
5056 {
Robert Konrad31afcbb2017-04-20 15:21:47 +02005057 if (!requires_op_fmod)
5058 {
5059 requires_op_fmod = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02005060 force_recompile();
Robert Konrad31afcbb2017-04-20 15:21:47 +02005061 }
Robert Konrad1a48d7d2016-08-18 12:54:22 +02005062 CompilerGLSL::emit_instruction(instruction);
5063 break;
5064 }
Robert Konrade7b02582017-03-24 13:58:39 +01005065
Hans-Kristian Arntzen3fa6cc82018-02-15 13:31:29 +01005066 case OpFRem:
5067 emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], "fmod");
5068 break;
5069
Robert Konradbb9dbd42017-04-24 11:08:55 +02005070 case OpImage:
5071 {
5072 uint32_t result_type = ops[0];
5073 uint32_t id = ops[1];
Hans-Kristian Arntzen988f00f2018-02-01 09:22:16 +01005074 auto *combined = maybe_get<SPIRCombinedImageSampler>(ops[2]);
Hans-Kristian Arntzena6972992018-10-05 09:49:57 +02005075
Hans-Kristian Arntzen988f00f2018-02-01 09:22:16 +01005076 if (combined)
Hans-Kristian Arntzena6972992018-10-05 09:49:57 +02005077 {
5078 auto &e = emit_op(result_type, id, to_expression(combined->image), true, true);
5079 auto *var = maybe_get_backing_variable(combined->image);
5080 if (var)
5081 e.loaded_from = var->self;
5082 }
Hans-Kristian Arntzen988f00f2018-02-01 09:22:16 +01005083 else
Hans-Kristian Arntzena6972992018-10-05 09:49:57 +02005084 {
5085 auto &e = emit_op(result_type, id, to_expression(ops[2]), true, true);
5086 auto *var = maybe_get_backing_variable(ops[2]);
5087 if (var)
5088 e.loaded_from = var->self;
5089 }
Robert Konradbb9dbd42017-04-24 11:08:55 +02005090 break;
5091 }
5092
Robert Konrade7b02582017-03-24 13:58:39 +01005093 case OpDPdx:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005094 HLSL_UFOP(ddx);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005095 register_control_dependent_expression(ops[1]);
Robert Konrade7b02582017-03-24 13:58:39 +01005096 break;
5097
5098 case OpDPdy:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005099 HLSL_UFOP(ddy);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005100 register_control_dependent_expression(ops[1]);
Robert Konrade7b02582017-03-24 13:58:39 +01005101 break;
5102
5103 case OpDPdxFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005104 HLSL_UFOP(ddx_fine);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005105 register_control_dependent_expression(ops[1]);
Robert Konrade7b02582017-03-24 13:58:39 +01005106 break;
5107
5108 case OpDPdyFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005109 HLSL_UFOP(ddy_fine);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005110 register_control_dependent_expression(ops[1]);
Robert Konrade7b02582017-03-24 13:58:39 +01005111 break;
5112
5113 case OpDPdxCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005114 HLSL_UFOP(ddx_coarse);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005115 register_control_dependent_expression(ops[1]);
Robert Konrade7b02582017-03-24 13:58:39 +01005116 break;
5117
5118 case OpDPdyCoarse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005119 HLSL_UFOP(ddy_coarse);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005120 register_control_dependent_expression(ops[1]);
Robert Konrade7b02582017-03-24 13:58:39 +01005121 break;
5122
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005123 case OpFwidth:
5124 case OpFwidthCoarse:
5125 case OpFwidthFine:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005126 HLSL_UFOP(fwidth);
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005127 register_control_dependent_expression(ops[1]);
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01005128 break;
5129
Robert Konrade7b02582017-03-24 13:58:39 +01005130 case OpLogicalNot:
5131 {
5132 auto result_type = ops[0];
5133 auto id = ops[1];
5134 auto &type = get<SPIRType>(result_type);
5135
5136 if (type.vecsize > 1)
Robert Konradf3a82772017-03-24 15:00:48 +01005137 emit_unrolled_unary_op(result_type, id, ops[2], "!");
Robert Konrade7b02582017-03-24 13:58:39 +01005138 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005139 HLSL_UOP(!);
Robert Konrade7b02582017-03-24 13:58:39 +01005140 break;
5141 }
5142
5143 case OpIEqual:
5144 {
5145 auto result_type = ops[0];
5146 auto id = ops[1];
5147
5148 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005149 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "==", false, SPIRType::Unknown);
Robert Konrade7b02582017-03-24 13:58:39 +01005150 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005151 HLSL_BOP_CAST(==, int_type);
Robert Konrade7b02582017-03-24 13:58:39 +01005152 break;
5153 }
5154
5155 case OpLogicalEqual:
5156 case OpFOrdEqual:
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005157 case OpFUnordEqual:
Robert Konrade7b02582017-03-24 13:58:39 +01005158 {
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005159 // HLSL != operator is unordered.
5160 // https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-float-rules.
5161 // isnan() is apparently implemented as x != x as well.
5162 // We cannot implement UnordEqual as !(OrdNotEqual), as HLSL cannot express OrdNotEqual.
5163 // HACK: FUnordEqual will be implemented as FOrdEqual.
5164
Robert Konrade7b02582017-03-24 13:58:39 +01005165 auto result_type = ops[0];
5166 auto id = ops[1];
5167
5168 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005169 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "==", false, SPIRType::Unknown);
Robert Konrade7b02582017-03-24 13:58:39 +01005170 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005171 HLSL_BOP(==);
Robert Konrade7b02582017-03-24 13:58:39 +01005172 break;
5173 }
5174
5175 case OpINotEqual:
5176 {
5177 auto result_type = ops[0];
5178 auto id = ops[1];
5179
5180 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005181 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!=", false, SPIRType::Unknown);
Robert Konrade7b02582017-03-24 13:58:39 +01005182 else
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01005183 HLSL_BOP_CAST(!=, int_type);
Robert Konrade7b02582017-03-24 13:58:39 +01005184 break;
5185 }
5186
5187 case OpLogicalNotEqual:
5188 case OpFOrdNotEqual:
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005189 case OpFUnordNotEqual:
Robert Konrade7b02582017-03-24 13:58:39 +01005190 {
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005191 // HLSL != operator is unordered.
5192 // https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-float-rules.
5193 // isnan() is apparently implemented as x != x as well.
5194
5195 // FIXME: FOrdNotEqual cannot be implemented in a crisp and simple way here.
5196 // We would need to do something like not(UnordEqual), but that cannot be expressed either.
5197 // Adding a lot of NaN checks would be a breaking change from perspective of performance.
5198 // SPIR-V will generally use isnan() checks when this even matters.
5199 // HACK: FOrdNotEqual will be implemented as FUnordEqual.
5200
Robert Konrade7b02582017-03-24 13:58:39 +01005201 auto result_type = ops[0];
5202 auto id = ops[1];
5203
5204 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005205 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!=", false, SPIRType::Unknown);
Robert Konrade7b02582017-03-24 13:58:39 +01005206 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005207 HLSL_BOP(!=);
Robert Konrade7b02582017-03-24 13:58:39 +01005208 break;
5209 }
5210
5211 case OpUGreaterThan:
5212 case OpSGreaterThan:
5213 {
5214 auto result_type = ops[0];
5215 auto id = ops[1];
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005216 auto type = opcode == OpUGreaterThan ? uint_type : int_type;
Robert Konrade7b02582017-03-24 13:58:39 +01005217
5218 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005219 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">", false, type);
Robert Konrade7b02582017-03-24 13:58:39 +01005220 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005221 HLSL_BOP_CAST(>, type);
Robert Konrade7b02582017-03-24 13:58:39 +01005222 break;
5223 }
5224
5225 case OpFOrdGreaterThan:
5226 {
5227 auto result_type = ops[0];
5228 auto id = ops[1];
5229
5230 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005231 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">", false, SPIRType::Unknown);
Robert Konrade7b02582017-03-24 13:58:39 +01005232 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005233 HLSL_BOP(>);
Robert Konrade7b02582017-03-24 13:58:39 +01005234 break;
5235 }
5236
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005237 case OpFUnordGreaterThan:
5238 {
5239 auto result_type = ops[0];
5240 auto id = ops[1];
5241
5242 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005243 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=", true, SPIRType::Unknown);
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005244 else
5245 CompilerGLSL::emit_instruction(instruction);
5246 break;
5247 }
5248
Robert Konrade7b02582017-03-24 13:58:39 +01005249 case OpUGreaterThanEqual:
5250 case OpSGreaterThanEqual:
5251 {
5252 auto result_type = ops[0];
5253 auto id = ops[1];
5254
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005255 auto type = opcode == OpUGreaterThanEqual ? uint_type : int_type;
Robert Konrade7b02582017-03-24 13:58:39 +01005256 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005257 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=", false, type);
Robert Konrade7b02582017-03-24 13:58:39 +01005258 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005259 HLSL_BOP_CAST(>=, type);
Robert Konrade7b02582017-03-24 13:58:39 +01005260 break;
5261 }
5262
5263 case OpFOrdGreaterThanEqual:
5264 {
5265 auto result_type = ops[0];
5266 auto id = ops[1];
5267
5268 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005269 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=", false, SPIRType::Unknown);
Robert Konrade7b02582017-03-24 13:58:39 +01005270 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005271 HLSL_BOP(>=);
Robert Konrade7b02582017-03-24 13:58:39 +01005272 break;
5273 }
5274
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005275 case OpFUnordGreaterThanEqual:
5276 {
5277 auto result_type = ops[0];
5278 auto id = ops[1];
5279
5280 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005281 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<", true, SPIRType::Unknown);
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005282 else
5283 CompilerGLSL::emit_instruction(instruction);
5284 break;
5285 }
5286
Robert Konrade7b02582017-03-24 13:58:39 +01005287 case OpULessThan:
5288 case OpSLessThan:
5289 {
5290 auto result_type = ops[0];
5291 auto id = ops[1];
5292
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005293 auto type = opcode == OpULessThan ? uint_type : int_type;
Robert Konrade7b02582017-03-24 13:58:39 +01005294 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005295 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<", false, type);
Robert Konrade7b02582017-03-24 13:58:39 +01005296 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005297 HLSL_BOP_CAST(<, type);
Robert Konrade7b02582017-03-24 13:58:39 +01005298 break;
5299 }
5300
5301 case OpFOrdLessThan:
5302 {
5303 auto result_type = ops[0];
5304 auto id = ops[1];
5305
5306 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005307 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<", false, SPIRType::Unknown);
Robert Konrade7b02582017-03-24 13:58:39 +01005308 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005309 HLSL_BOP(<);
Robert Konrade7b02582017-03-24 13:58:39 +01005310 break;
5311 }
5312
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005313 case OpFUnordLessThan:
5314 {
5315 auto result_type = ops[0];
5316 auto id = ops[1];
5317
5318 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005319 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=", true, SPIRType::Unknown);
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005320 else
5321 CompilerGLSL::emit_instruction(instruction);
5322 break;
5323 }
5324
Robert Konrade7b02582017-03-24 13:58:39 +01005325 case OpULessThanEqual:
5326 case OpSLessThanEqual:
5327 {
5328 auto result_type = ops[0];
5329 auto id = ops[1];
5330
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005331 auto type = opcode == OpULessThanEqual ? uint_type : int_type;
Robert Konrade7b02582017-03-24 13:58:39 +01005332 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005333 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=", false, type);
Robert Konrade7b02582017-03-24 13:58:39 +01005334 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005335 HLSL_BOP_CAST(<=, type);
Robert Konrade7b02582017-03-24 13:58:39 +01005336 break;
5337 }
5338
5339 case OpFOrdLessThanEqual:
5340 {
5341 auto result_type = ops[0];
5342 auto id = ops[1];
5343
5344 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005345 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=", false, SPIRType::Unknown);
Robert Konrade7b02582017-03-24 13:58:39 +01005346 else
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005347 HLSL_BOP(<=);
Robert Konrade7b02582017-03-24 13:58:39 +01005348 break;
5349 }
5350
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005351 case OpFUnordLessThanEqual:
5352 {
5353 auto result_type = ops[0];
5354 auto id = ops[1];
5355
5356 if (expression_type(ops[2]).vecsize > 1)
Hans-Kristian Arntzena9be9252019-10-14 16:08:39 +02005357 emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">", true, SPIRType::Unknown);
Hans-Kristian Arntzenb960ae32019-10-14 15:04:00 +02005358 else
5359 CompilerGLSL::emit_instruction(instruction);
5360 break;
5361 }
5362
Hans-Kristian Arntzenaeeb0e32017-12-01 13:28:51 +01005363 case OpImageQueryLod:
Hans-Kristian Arntzen275974e2020-06-04 15:50:28 +02005364 emit_texture_op(instruction, false);
Hans-Kristian Arntzenaeeb0e32017-12-01 13:28:51 +01005365 break;
5366
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02005367 case OpImageQuerySizeLod:
5368 {
5369 auto result_type = ops[0];
5370 auto id = ops[1];
5371
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005372 require_texture_query_variant(ops[2]);
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02005373 auto dummy_samples_levels = join(get_fallback_name(id), "_dummy_parameter");
5374 statement("uint ", dummy_samples_levels, ";");
5375
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005376 auto expr = join("spvTextureSize(", to_non_uniform_aware_expression(ops[2]), ", ",
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02005377 bitcast_expression(SPIRType::UInt, ops[3]), ", ", dummy_samples_levels, ")");
5378
5379 auto &restype = get<SPIRType>(ops[0]);
5380 expr = bitcast_expression(restype, SPIRType::UInt, expr);
5381 emit_op(result_type, id, expr, true);
5382 break;
5383 }
5384
5385 case OpImageQuerySize:
5386 {
5387 auto result_type = ops[0];
5388 auto id = ops[1];
5389
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005390 require_texture_query_variant(ops[2]);
5391 bool uav = expression_type(ops[2]).image.sampled == 2;
5392
5393 if (const auto *var = maybe_get_backing_variable(ops[2]))
5394 if (hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(var->self, DecorationNonWritable))
5395 uav = false;
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02005396
5397 auto dummy_samples_levels = join(get_fallback_name(id), "_dummy_parameter");
5398 statement("uint ", dummy_samples_levels, ";");
5399
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005400 string expr;
5401 if (uav)
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005402 expr = join("spvImageSize(", to_non_uniform_aware_expression(ops[2]), ", ", dummy_samples_levels, ")");
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005403 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005404 expr = join("spvTextureSize(", to_non_uniform_aware_expression(ops[2]), ", 0u, ", dummy_samples_levels, ")");
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005405
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02005406 auto &restype = get<SPIRType>(ops[0]);
5407 expr = bitcast_expression(restype, SPIRType::UInt, expr);
5408 emit_op(result_type, id, expr, true);
5409 break;
5410 }
5411
5412 case OpImageQuerySamples:
5413 case OpImageQueryLevels:
5414 {
5415 auto result_type = ops[0];
5416 auto id = ops[1];
5417
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005418 require_texture_query_variant(ops[2]);
5419 bool uav = expression_type(ops[2]).image.sampled == 2;
5420 if (opcode == OpImageQueryLevels && uav)
5421 SPIRV_CROSS_THROW("Cannot query levels for UAV images.");
5422
5423 if (const auto *var = maybe_get_backing_variable(ops[2]))
5424 if (hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(var->self, DecorationNonWritable))
5425 uav = false;
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02005426
5427 // Keep it simple and do not emit special variants to make this look nicer ...
5428 // This stuff is barely, if ever, used.
5429 forced_temporaries.insert(id);
5430 auto &type = get<SPIRType>(result_type);
5431 statement(variable_decl(type, to_name(id)), ";");
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005432
5433 if (uav)
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005434 statement("spvImageSize(", to_non_uniform_aware_expression(ops[2]), ", ", to_name(id), ");");
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005435 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005436 statement("spvTextureSize(", to_non_uniform_aware_expression(ops[2]), ", 0u, ", to_name(id), ");");
Hans-Kristian Arntzen1bc5b702017-09-20 09:59:32 +02005437
5438 auto &restype = get<SPIRType>(ops[0]);
5439 auto expr = bitcast_expression(restype, SPIRType::UInt, to_name(id));
5440 set<SPIRExpression>(id, expr, result_type, true);
5441 break;
5442 }
5443
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005444 case OpImageRead:
5445 {
5446 uint32_t result_type = ops[0];
5447 uint32_t id = ops[1];
5448 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01005449 auto &type = expression_type(ops[2]);
5450 bool subpass_data = type.image.dim == DimSubpassData;
5451 bool pure = false;
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005452
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01005453 string imgexpr;
5454
5455 if (subpass_data)
5456 {
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01005457 if (hlsl_options.shader_model < 40)
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01005458 SPIRV_CROSS_THROW("Subpass loads are not supported in HLSL shader model 2/3.");
5459
5460 // Similar to GLSL, implement subpass loads using texelFetch.
5461 if (type.image.ms)
5462 {
5463 uint32_t operands = ops[4];
5464 if (operands != ImageOperandsSampleMask || instruction.length != 6)
5465 SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected operand mask was used.");
5466 uint32_t sample = ops[5];
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005467 imgexpr = join(to_non_uniform_aware_expression(ops[2]), ".Load(int2(gl_FragCoord.xy), ", to_expression(sample), ")");
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01005468 }
5469 else
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005470 imgexpr = join(to_non_uniform_aware_expression(ops[2]), ".Load(int3(int2(gl_FragCoord.xy), 0))");
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01005471
5472 pure = true;
5473 }
5474 else
5475 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005476 imgexpr = join(to_non_uniform_aware_expression(ops[2]), "[", to_expression(ops[3]), "]");
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01005477 // The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4",
5478 // except that the underlying type changes how the data is interpreted.
Hans-Kristian Arntzen28bf9052020-04-03 11:21:41 +02005479
5480 bool force_srv =
5481 hlsl_options.nonwritable_uav_texture_as_srv && var && has_decoration(var->self, DecorationNonWritable);
5482 pure = force_srv;
5483
5484 if (var && !subpass_data && !force_srv)
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01005485 imgexpr = remap_swizzle(get<SPIRType>(result_type),
5486 image_format_to_components(get<SPIRType>(var->basetype).image.format), imgexpr);
5487 }
Hans-Kristian Arntzena95295c2017-10-24 09:52:12 +02005488
Hans-Kristian Arntzen476b6542022-03-04 11:05:21 +01005489 if (var)
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005490 {
Hans-Kristian Arntzenc65248f2017-11-29 12:13:48 +01005491 bool forward = forced_temporaries.find(id) == end(forced_temporaries);
5492 auto &e = emit_op(result_type, id, imgexpr, forward);
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01005493
5494 if (!pure)
5495 {
5496 e.loaded_from = var->self;
5497 if (forward)
5498 var->dependees.push_back(id);
5499 }
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005500 }
5501 else
5502 emit_op(result_type, id, imgexpr, false);
Hans-Kristian Arntzene0efa732018-03-09 13:21:38 +01005503
5504 inherit_expression_dependencies(id, ops[2]);
5505 if (type.image.ms)
5506 inherit_expression_dependencies(id, ops[5]);
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005507 break;
5508 }
5509
5510 case OpImageWrite:
5511 {
5512 auto *var = maybe_get_backing_variable(ops[0]);
Hans-Kristian Arntzena95295c2017-10-24 09:52:12 +02005513
5514 // The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4",
5515 // except that the underlying type changes how the data is interpreted.
5516 auto value_expr = to_expression(ops[2]);
5517 if (var)
5518 {
5519 auto &type = get<SPIRType>(var->basetype);
5520 auto narrowed_type = get<SPIRType>(type.image.type);
5521 narrowed_type.vecsize = image_format_to_components(type.image.format);
5522 value_expr = remap_swizzle(narrowed_type, expression_type(ops[2]).vecsize, value_expr);
5523 }
5524
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005525 statement(to_non_uniform_aware_expression(ops[0]), "[", to_expression(ops[1]), "] = ", value_expr, ";");
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005526 if (var && variable_storage_is_aliased(*var))
5527 flush_all_aliased_variables();
5528 break;
5529 }
5530
5531 case OpImageTexelPointer:
5532 {
5533 uint32_t result_type = ops[0];
5534 uint32_t id = ops[1];
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +01005535
5536 auto expr = to_expression(ops[2]);
Hans-Kristian Arntzena3d3c802020-03-19 11:35:06 +01005537 expr += join("[", to_expression(ops[3]), "]");
Hans-Kristian Arntzen04e877d2020-03-19 14:20:37 +01005538 auto &e = set<SPIRExpression>(id, expr, result_type, true);
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005539
5540 // When using the pointer, we need to know which variable it is actually loaded from.
5541 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005542 e.loaded_from = var ? var->self : ID(0);
Hans-Kristian Arntzen6edbf0c2019-10-24 11:30:20 +02005543 inherit_expression_dependencies(id, ops[3]);
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005544 break;
5545 }
5546
5547 case OpAtomicCompareExchange:
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005548 case OpAtomicExchange:
5549 case OpAtomicISub:
5550 case OpAtomicSMin:
5551 case OpAtomicUMin:
5552 case OpAtomicSMax:
5553 case OpAtomicUMax:
5554 case OpAtomicAnd:
5555 case OpAtomicOr:
5556 case OpAtomicXor:
5557 case OpAtomicIAdd:
Hans-Kristian Arntzen73771522018-09-17 15:46:39 +02005558 case OpAtomicIIncrement:
5559 case OpAtomicIDecrement:
Hans-Kristian Arntzen9b7140e2020-04-27 12:09:59 +02005560 case OpAtomicLoad:
5561 case OpAtomicStore:
Hans-Kristian Arntzen044d3c82017-10-20 14:56:37 +02005562 {
5563 emit_atomic(ops, instruction.length, opcode);
5564 break;
5565 }
5566
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +01005567 case OpControlBarrier:
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02005568 case OpMemoryBarrier:
5569 {
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +01005570 uint32_t memory;
5571 uint32_t semantics;
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02005572
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +01005573 if (opcode == OpMemoryBarrier)
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02005574 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02005575 memory = evaluate_constant_u32(ops[0]);
5576 semantics = evaluate_constant_u32(ops[1]);
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02005577 }
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02005578 else
5579 {
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02005580 memory = evaluate_constant_u32(ops[1]);
5581 semantics = evaluate_constant_u32(ops[2]);
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +01005582 }
5583
Hans-Kristian Arntzenc2664292018-04-11 15:02:02 +02005584 if (memory == ScopeSubgroup)
5585 {
5586 // No Wave-barriers in HLSL.
5587 break;
5588 }
5589
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +01005590 // We only care about these flags, acquire/release and friends are not relevant to GLSL.
5591 semantics = mask_relevant_memory_semantics(semantics);
5592
5593 if (opcode == OpMemoryBarrier)
5594 {
5595 // If we are a memory barrier, and the next instruction is a control barrier, check if that memory barrier
5596 // does what we need, so we avoid redundant barriers.
5597 const Instruction *next = get_next_instruction_in_block(instruction);
5598 if (next && next->op == OpControlBarrier)
5599 {
5600 auto *next_ops = stream(*next);
Hans-Kristian Arntzen66afe8c2020-09-14 10:42:31 +02005601 uint32_t next_memory = evaluate_constant_u32(next_ops[1]);
5602 uint32_t next_semantics = evaluate_constant_u32(next_ops[2]);
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +01005603 next_semantics = mask_relevant_memory_semantics(next_semantics);
5604
5605 // There is no "just execution barrier" in HLSL.
5606 // If there are no memory semantics for next instruction, we will imply group shared memory is synced.
5607 if (next_semantics == 0)
5608 next_semantics = MemorySemanticsWorkgroupMemoryMask;
5609
5610 bool memory_scope_covered = false;
5611 if (next_memory == memory)
5612 memory_scope_covered = true;
5613 else if (next_semantics == MemorySemanticsWorkgroupMemoryMask)
5614 {
5615 // If we only care about workgroup memory, either Device or Workgroup scope is fine,
5616 // scope does not have to match.
5617 if ((next_memory == ScopeDevice || next_memory == ScopeWorkgroup) &&
5618 (memory == ScopeDevice || memory == ScopeWorkgroup))
5619 {
5620 memory_scope_covered = true;
5621 }
5622 }
5623 else if (memory == ScopeWorkgroup && next_memory == ScopeDevice)
5624 {
5625 // The control barrier has device scope, but the memory barrier just has workgroup scope.
5626 memory_scope_covered = true;
5627 }
5628
5629 // If we have the same memory scope, and all memory types are covered, we're good.
5630 if (memory_scope_covered && (semantics & next_semantics) == semantics)
5631 break;
5632 }
5633 }
5634
5635 // We are synchronizing some memory or syncing execution,
5636 // so we cannot forward any loads beyond the memory barrier.
5637 if (semantics || opcode == OpControlBarrier)
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005638 {
5639 assert(current_emitting_block);
5640 flush_control_dependent_expressions(current_emitting_block->self);
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +01005641 flush_all_active_variables();
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +01005642 }
Hans-Kristian Arntzen9c3d4e72018-01-09 12:41:13 +01005643
5644 if (opcode == OpControlBarrier)
5645 {
5646 // We cannot emit just execution barrier, for no memory semantics pick the cheapest option.
5647 if (semantics == MemorySemanticsWorkgroupMemoryMask || semantics == 0)
5648 statement("GroupMemoryBarrierWithGroupSync();");
5649 else if (semantics != 0 && (semantics & MemorySemanticsWorkgroupMemoryMask) == 0)
5650 statement("DeviceMemoryBarrierWithGroupSync();");
5651 else
5652 statement("AllMemoryBarrierWithGroupSync();");
5653 }
5654 else
5655 {
5656 if (semantics == MemorySemanticsWorkgroupMemoryMask)
5657 statement("GroupMemoryBarrier();");
5658 else if (semantics != 0 && (semantics & MemorySemanticsWorkgroupMemoryMask) == 0)
5659 statement("DeviceMemoryBarrier();");
5660 else
5661 statement("AllMemoryBarrier();");
Hans-Kristian Arntzenae236e72017-10-20 16:18:02 +02005662 }
5663 break;
5664 }
5665
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005666 case OpBitFieldInsert:
5667 {
5668 if (!requires_bitfield_insert)
5669 {
5670 requires_bitfield_insert = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02005671 force_recompile();
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005672 }
5673
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01005674 auto expr = join("spvBitfieldInsert(", to_expression(ops[2]), ", ", to_expression(ops[3]), ", ",
Hans-Kristian Arntzenc4052742017-11-29 12:00:48 +01005675 to_expression(ops[4]), ", ", to_expression(ops[5]), ")");
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005676
Hans-Kristian Arntzenc4052742017-11-29 12:00:48 +01005677 bool forward =
5678 should_forward(ops[2]) && should_forward(ops[3]) && should_forward(ops[4]) && should_forward(ops[5]);
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005679
5680 auto &restype = get<SPIRType>(ops[0]);
5681 expr = bitcast_expression(restype, SPIRType::UInt, expr);
5682 emit_op(ops[0], ops[1], expr, forward);
5683 break;
5684 }
5685
5686 case OpBitFieldSExtract:
5687 case OpBitFieldUExtract:
5688 {
5689 if (!requires_bitfield_extract)
5690 {
5691 requires_bitfield_extract = true;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02005692 force_recompile();
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005693 }
5694
5695 if (opcode == OpBitFieldSExtract)
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01005696 HLSL_TFOP(spvBitfieldSExtract);
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005697 else
Hans-Kristian Arntzen6a614cc2020-11-23 15:42:27 +01005698 HLSL_TFOP(spvBitfieldUExtract);
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005699 break;
5700 }
5701
5702 case OpBitCount:
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005703 {
5704 auto basetype = expression_type(ops[2]).basetype;
5705 emit_unary_func_op_cast(ops[0], ops[1], ops[2], "countbits", basetype, basetype);
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005706 break;
Hans-Kristian Arntzenb3305792019-08-26 11:01:14 +02005707 }
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005708
5709 case OpBitReverse:
Hans-Kristian Arntzenf1752e52018-06-28 22:57:52 +02005710 HLSL_UFOP(reversebits);
Hans-Kristian Arntzen48f3fa42017-11-29 11:33:44 +01005711 break;
5712
Hans-Kristian Arntzene9da5ed2019-05-07 15:49:38 +02005713 case OpArrayLength:
5714 {
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005715 auto *var = maybe_get_backing_variable(ops[2]);
Hans-Kristian Arntzene9da5ed2019-05-07 15:49:38 +02005716 if (!var)
5717 SPIRV_CROSS_THROW("Array length must point directly to an SSBO block.");
5718
5719 auto &type = get<SPIRType>(var->basetype);
5720 if (!has_decoration(type.self, DecorationBlock) && !has_decoration(type.self, DecorationBufferBlock))
5721 SPIRV_CROSS_THROW("Array length expression must point to a block type.");
5722
5723 // This must be 32-bit uint, so we're good to go.
5724 emit_uninitialized_temporary_expression(ops[0], ops[1]);
Hans-Kristian Arntzen532f6552021-04-22 13:54:43 +02005725 statement(to_non_uniform_aware_expression(ops[2]), ".GetDimensions(", to_expression(ops[1]), ");");
Hans-Kristian Arntzene9da5ed2019-05-07 15:49:38 +02005726 uint32_t offset = type_struct_member_offset(type, ops[3]);
5727 uint32_t stride = type_struct_member_array_stride(type, ops[3]);
5728 statement(to_expression(ops[1]), " = (", to_expression(ops[1]), " - ", offset, ") / ", stride, ";");
5729 break;
5730 }
5731
Chip Davis50dce102019-07-13 15:57:33 -05005732 case OpIsHelperInvocationEXT:
Pedro J. Estébanezc4f9e4f2022-03-04 13:05:26 +01005733 if (hlsl_options.shader_model < 50 || get_entry_point().model != ExecutionModelFragment)
Hans-Kristian Arntzen005c14a2022-03-04 10:54:31 +01005734 SPIRV_CROSS_THROW("Helper Invocation input is only supported in PS 5.0 or higher.");
5735 // Helper lane state with demote is volatile by nature.
5736 // Do not forward this.
5737 emit_op(ops[0], ops[1], "IsHelperLane()", false);
5738 break;
Chip Davis50dce102019-07-13 15:57:33 -05005739
Chip Davis2eff4202019-08-04 00:07:20 -05005740 case OpBeginInvocationInterlockEXT:
5741 case OpEndInvocationInterlockEXT:
5742 if (hlsl_options.shader_model < 51)
5743 SPIRV_CROSS_THROW("Rasterizer order views require Shader Model 5.1.");
5744 break; // Nothing to do in the body
5745
Konstantin Pail251361b2022-03-15 21:54:29 +03005746 case OpRayQueryInitializeKHR:
5747 {
5748 flush_variable_declaration(ops[0]);
5749
5750 std::string ray_desc_name = get_unique_identifier();
5751 statement("RayDesc ", ray_desc_name, " = {", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
5752 to_expression(ops[6]), ", ", to_expression(ops[7]), "};");
5753
5754 statement(to_expression(ops[0]), ".TraceRayInline(",
5755 to_expression(ops[1]), ", ", // acc structure
5756 to_expression(ops[2]), ", ", // ray flags
5757 to_expression(ops[3]), ", ", // mask
5758 ray_desc_name, ");"); // ray
5759 break;
5760 }
5761 case OpRayQueryProceedKHR:
5762 {
5763 flush_variable_declaration(ops[0]);
5764 emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".Proceed()"), false);
5765 break;
5766 }
5767 case OpRayQueryTerminateKHR:
5768 {
5769 flush_variable_declaration(ops[0]);
5770 statement(to_expression(ops[0]), ".Abort();");
5771 break;
5772 }
5773 case OpRayQueryGenerateIntersectionKHR:
5774 {
5775 flush_variable_declaration(ops[0]);
5776 statement(to_expression(ops[0]), ".CommitProceduralPrimitiveHit(", ops[1], ");");
5777 break;
5778 }
5779 case OpRayQueryConfirmIntersectionKHR:
5780 {
5781 flush_variable_declaration(ops[0]);
5782 statement(to_expression(ops[0]), ".CommitNonOpaqueTriangleHit();");
5783 break;
5784 }
5785 case OpRayQueryGetIntersectionTypeKHR:
5786 {
5787 emit_rayquery_function(".CommittedStatus()", ".CandidateType()", ops);
5788 break;
5789 }
5790 case OpRayQueryGetIntersectionTKHR:
5791 {
5792 emit_rayquery_function(".CommittedRayT()", ".CandidateTriangleRayT()", ops);
5793 break;
5794 }
5795 case OpRayQueryGetIntersectionInstanceCustomIndexKHR:
5796 {
5797 emit_rayquery_function(".CommittedInstanceID()", ".CandidateInstanceID()", ops);
5798 break;
5799 }
5800 case OpRayQueryGetIntersectionInstanceIdKHR:
5801 {
5802 emit_rayquery_function(".CommittedInstanceIndex()", ".CandidateInstanceIndex()", ops);
5803 break;
5804 }
5805 case OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR:
5806 {
5807 emit_rayquery_function(".CommittedInstanceContributionToHitGroupIndex()",
5808 ".CandidateInstanceContributionToHitGroupIndex()", ops);
5809 break;
5810 }
5811 case OpRayQueryGetIntersectionGeometryIndexKHR:
5812 {
5813 emit_rayquery_function(".CommittedGeometryIndex()",
5814 ".CandidateGeometryIndex()", ops);
5815 break;
5816 }
5817 case OpRayQueryGetIntersectionPrimitiveIndexKHR:
5818 {
5819 emit_rayquery_function(".CommittedPrimitiveIndex()", ".CandidatePrimitiveIndex()", ops);
5820 break;
5821 }
5822 case OpRayQueryGetIntersectionBarycentricsKHR:
5823 {
5824 emit_rayquery_function(".CommittedTriangleBarycentrics()", ".CandidateTriangleBarycentrics()", ops);
5825 break;
5826 }
5827 case OpRayQueryGetIntersectionFrontFaceKHR:
5828 {
5829 emit_rayquery_function(".CommittedTriangleFrontFace()", ".CandidateTriangleFrontFace()", ops);
5830 break;
5831 }
5832 case OpRayQueryGetIntersectionCandidateAABBOpaqueKHR:
5833 {
5834 flush_variable_declaration(ops[0]);
5835 emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".CandidateProceduralPrimitiveNonOpaque()"), false);
5836 break;
5837 }
5838 case OpRayQueryGetIntersectionObjectRayDirectionKHR:
5839 {
5840 emit_rayquery_function(".CommittedObjectRayDirection()", ".CandidateObjectRayDirection()", ops);
5841 break;
5842 }
5843 case OpRayQueryGetIntersectionObjectRayOriginKHR:
5844 {
5845 flush_variable_declaration(ops[0]);
5846 emit_rayquery_function(".CommittedObjectRayOrigin()", ".CandidateObjectRayOrigin()", ops);
5847 break;
5848 }
5849 case OpRayQueryGetIntersectionObjectToWorldKHR:
5850 {
5851 emit_rayquery_function(".CommittedObjectToWorld4x3()", ".CandidateObjectToWorld4x3()", ops);
5852 break;
5853 }
5854 case OpRayQueryGetIntersectionWorldToObjectKHR:
5855 {
5856 emit_rayquery_function(".CommittedWorldToObject4x3()", ".CandidateWorldToObject4x3()", ops);
5857 break;
5858 }
5859 case OpRayQueryGetRayFlagsKHR:
5860 {
5861 flush_variable_declaration(ops[0]);
5862 emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".RayFlags()"), false);
5863 break;
5864 }
5865 case OpRayQueryGetRayTMinKHR:
5866 {
5867 flush_variable_declaration(ops[0]);
5868 emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".RayTMin()"), false);
5869 break;
5870 }
5871 case OpRayQueryGetWorldRayOriginKHR:
5872 {
5873 flush_variable_declaration(ops[0]);
5874 emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".WorldRayOrigin()"), false);
5875 break;
5876 }
5877 case OpRayQueryGetWorldRayDirectionKHR:
5878 {
5879 flush_variable_declaration(ops[0]);
5880 emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".WorldRayDirection()"), false);
5881 break;
5882 }
Robert Konradda5f99b2016-08-14 23:54:51 +02005883 default:
5884 CompilerGLSL::emit_instruction(instruction);
5885 break;
5886 }
5887}
5888
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005889void CompilerHLSL::require_texture_query_variant(uint32_t var_id)
Hans-Kristian Arntzen9aa42a82017-09-20 10:31:05 +02005890{
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005891 if (const auto *var = maybe_get_backing_variable(var_id))
5892 var_id = var->self;
5893
5894 auto &type = expression_type(var_id);
5895 bool uav = type.image.sampled == 2;
5896 if (hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(var_id, DecorationNonWritable))
5897 uav = false;
5898
Hans-Kristian Arntzen9aa42a82017-09-20 10:31:05 +02005899 uint32_t bit = 0;
5900 switch (type.image.dim)
5901 {
5902 case Dim1D:
5903 bit = type.image.arrayed ? Query1DArray : Query1D;
5904 break;
5905
5906 case Dim2D:
5907 if (type.image.ms)
5908 bit = type.image.arrayed ? Query2DMSArray : Query2DMS;
5909 else
5910 bit = type.image.arrayed ? Query2DArray : Query2D;
5911 break;
5912
5913 case Dim3D:
5914 bit = Query3D;
5915 break;
5916
5917 case DimCube:
5918 bit = type.image.arrayed ? QueryCubeArray : QueryCube;
5919 break;
5920
5921 case DimBuffer:
5922 bit = QueryBuffer;
5923 break;
5924
5925 default:
5926 SPIRV_CROSS_THROW("Unsupported query type.");
5927 }
5928
5929 switch (get<SPIRType>(type.image.type).basetype)
5930 {
5931 case SPIRType::Float:
5932 bit += QueryTypeFloat;
5933 break;
5934
5935 case SPIRType::Int:
5936 bit += QueryTypeInt;
5937 break;
5938
5939 case SPIRType::UInt:
5940 bit += QueryTypeUInt;
5941 break;
5942
5943 default:
5944 SPIRV_CROSS_THROW("Unsupported query type.");
5945 }
5946
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005947 auto norm_state = image_format_to_normalized_state(type.image.format);
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02005948 auto &variant = uav ? required_texture_size_variants
5949 .uav[uint32_t(norm_state)][image_format_to_components(type.image.format) - 1] :
5950 required_texture_size_variants.srv;
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005951
Hans-Kristian Arntzen9aa42a82017-09-20 10:31:05 +02005952 uint64_t mask = 1ull << bit;
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005953 if ((variant & mask) == 0)
Hans-Kristian Arntzen9aa42a82017-09-20 10:31:05 +02005954 {
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02005955 force_recompile();
Hans-Kristian Arntzenf3a362b2020-05-19 13:39:48 +02005956 variant |= mask;
Hans-Kristian Arntzen9aa42a82017-09-20 10:31:05 +02005957 }
5958}
5959
Hans-Kristian Arntzen3fe57d32019-04-09 12:46:23 +02005960void CompilerHLSL::set_root_constant_layouts(std::vector<RootConstants> layout)
Amer Koleci7216d132017-11-06 20:10:04 +01005961{
Daniel Thornburgh44c33332022-03-02 23:02:38 +00005962 root_constants_layout = std::move(layout);
Hans-Kristian Arntzen9bbdccd2019-02-12 11:11:29 +01005963}
5964
5965void CompilerHLSL::add_vertex_attribute_remap(const HLSLVertexAttributeRemap &vertex_attributes)
5966{
5967 remap_vertex_attributes.push_back(vertex_attributes);
Amer Koleci7216d132017-11-06 20:10:04 +01005968}
5969
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02005970VariableID CompilerHLSL::remap_num_workgroups_builtin()
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01005971{
5972 update_active_builtins();
Hans-Kristian Arntzenf6d08e62018-02-23 15:56:25 +01005973
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01005974 if (!active_input_builtins.get(BuiltInNumWorkgroups))
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01005975 return 0;
5976
5977 // Create a new, fake UBO.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02005978 uint32_t offset = ir.increase_bound_by(4);
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01005979
5980 uint32_t uint_type_id = offset;
5981 uint32_t block_type_id = offset + 1;
5982 uint32_t block_pointer_type_id = offset + 2;
5983 uint32_t variable_id = offset + 3;
5984
5985 SPIRType uint_type;
5986 uint_type.basetype = SPIRType::UInt;
Hans-Kristian Arntzen6a0f6982018-02-14 09:22:29 +01005987 uint_type.width = 32;
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01005988 uint_type.vecsize = 3;
5989 uint_type.columns = 1;
5990 set<SPIRType>(uint_type_id, uint_type);
5991
5992 SPIRType block_type;
5993 block_type.basetype = SPIRType::Struct;
5994 block_type.member_types.push_back(uint_type_id);
5995 set<SPIRType>(block_type_id, block_type);
5996 set_decoration(block_type_id, DecorationBlock);
5997 set_member_name(block_type_id, 0, "count");
5998 set_member_decoration(block_type_id, 0, DecorationOffset, 0);
5999
6000 SPIRType block_pointer_type = block_type;
6001 block_pointer_type.pointer = true;
6002 block_pointer_type.storage = StorageClassUniform;
6003 block_pointer_type.parent_type = block_type_id;
6004 auto &ptr_type = set<SPIRType>(block_pointer_type_id, block_pointer_type);
6005
6006 // Preserve self.
6007 ptr_type.self = block_type_id;
6008
6009 set<SPIRVariable>(variable_id, block_pointer_type_id, StorageClassUniform);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02006010 ir.meta[variable_id].decoration.alias = "SPIRV_Cross_NumWorkgroups";
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01006011
6012 num_workgroups_builtin = variable_id;
Hans-Kristian Arntzen9b2a8c72021-09-30 14:39:42 +02006013 get_entry_point().interface_variables.push_back(num_workgroups_builtin);
Hans-Kristian Arntzen18e88332018-02-05 10:27:42 +01006014 return variable_id;
6015}
6016
Hans-Kristian Arntzenb9e5fe02019-11-11 11:01:35 +01006017void CompilerHLSL::set_resource_binding_flags(HLSLBindingFlags flags)
6018{
6019 resource_binding_flags = flags;
6020}
6021
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +02006022void CompilerHLSL::validate_shader_model()
6023{
6024 // Check for nonuniform qualifier.
6025 // Instead of looping over all decorations to find this, just look at capabilities.
6026 for (auto &cap : ir.declared_capabilities)
6027 {
6028 switch (cap)
6029 {
6030 case CapabilityShaderNonUniformEXT:
6031 case CapabilityRuntimeDescriptorArrayEXT:
6032 if (hlsl_options.shader_model < 51)
Hans-Kristian Arntzen45a36ad2019-05-14 09:54:35 +02006033 SPIRV_CROSS_THROW(
6034 "Shader model 5.1 or higher is required to use bindless resources or NonUniformResourceIndex.");
Hans-Kristian Arntzendc940842020-12-07 12:16:02 +01006035 break;
6036
6037 case CapabilityVariablePointers:
6038 case CapabilityVariablePointersStorageBuffer:
6039 SPIRV_CROSS_THROW("VariablePointers capability is not supported in HLSL.");
6040
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +02006041 default:
6042 break;
6043 }
6044 }
6045
6046 if (ir.addressing_model != AddressingModelLogical)
6047 SPIRV_CROSS_THROW("Only Logical addressing model can be used with HLSL.");
Hans-Kristian Arntzen2d520062020-06-04 11:35:21 +02006048
6049 if (hlsl_options.enable_16bit_types && hlsl_options.shader_model < 62)
6050 SPIRV_CROSS_THROW("Need at least shader model 6.2 when enabling native 16-bit type support.");
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +02006051}
6052
Robert Konrad45270f62016-08-14 16:21:43 +02006053string CompilerHLSL::compile()
6054{
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +02006055 ir.fixup_reserved_names();
6056
Robert Konrad45270f62016-08-14 16:21:43 +02006057 // Do not deal with ES-isms like precision, older extensions and such.
Hans-Kristian Arntzena803e5a2018-03-09 15:25:25 +01006058 options.es = false;
6059 options.version = 450;
6060 options.vulkan_semantics = true;
Robert Konrad45270f62016-08-14 16:21:43 +02006061 backend.float_literal_suffix = true;
6062 backend.double_literal_suffix = false;
6063 backend.long_long_literal_suffix = true;
6064 backend.uint32_t_literal_suffix = true;
Hans-Kristian Arntzen3fa09f52019-03-29 09:44:32 +01006065 backend.int16_t_literal_suffix = "";
Chip Davisca4744a2018-11-02 14:39:55 -05006066 backend.uint16_t_literal_suffix = "u";
Robert Konradd2b29c92016-08-14 23:09:06 +02006067 backend.basic_int_type = "int";
6068 backend.basic_uint_type = "uint";
Chip Davis50dce102019-07-13 15:57:33 -05006069 backend.demote_literal = "discard";
Chip Davis6628ea62019-07-10 23:46:40 -05006070 backend.boolean_mix_function = "";
Robert Konradd2b29c92016-08-14 23:09:06 +02006071 backend.swizzle_is_function = false;
Robert Konrad45270f62016-08-14 16:21:43 +02006072 backend.shared_is_implied = true;
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +02006073 backend.unsized_array_supported = true;
Hans-Kristian Arntzenbdea1a42017-03-06 16:50:15 +01006074 backend.explicit_struct_type = false;
Robert Konrad45270f62016-08-14 16:21:43 +02006075 backend.use_initializer_list = true;
Robert Konradea24ee82016-09-23 18:57:18 +02006076 backend.use_constructor_splatting = false;
Hans-Kristian Arntzen95073252017-12-12 11:03:46 +01006077 backend.can_swizzle_scalar = true;
Hans-Kristian Arntzen06041982018-01-23 16:36:20 +01006078 backend.can_declare_struct_inline = false;
Hans-Kristian Arntzen5d9df6a2018-02-02 10:10:17 +01006079 backend.can_declare_arrays_inline = false;
Hans-Kristian Arntzen00ccd592018-02-05 12:37:41 +01006080 backend.can_return_array = false;
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +02006081 backend.nonuniform_qualifier = "NonUniformResourceIndex";
Hans-Kristian Arntzen581ed0f2019-06-27 15:10:17 +02006082 backend.support_case_fallthrough = false;
Robert Konrade9cd04e2016-08-14 22:02:38 +02006083
Hans-Kristian Arntzene47a30e2021-05-07 12:28:08 +02006084 // SM 4.1 does not support precise for some reason.
6085 backend.support_precise_qualifier = hlsl_options.shader_model >= 50 || hlsl_options.shader_model == 40;
6086
Hans-Kristian Arntzen4ab5bbb2022-03-10 15:38:57 +01006087 fixup_anonymous_struct_names();
Hans-Kristian Arntzen96492642019-05-23 14:54:04 +02006088 fixup_type_alias();
6089 reorder_type_alias();
Hans-Kristian Arntzenb5ed7062018-07-05 10:42:05 +02006090 build_function_control_flow_graphs_and_analyze();
Hans-Kristian Arntzen647ddae2019-05-13 14:58:27 +02006091 validate_shader_model();
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01006092 update_active_builtins();
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01006093 analyze_image_and_sampler_usage();
Hans-Kristian Arntzen261b4692019-09-04 12:18:04 +02006094 analyze_interlocked_resource_usage();
Hans-Kristian Arntzen18a594a2018-02-09 10:26:20 +01006095
6096 // Subpass input needs SV_Position.
6097 if (need_subpass_input)
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01006098 active_input_builtins.set(BuiltInFragCoord);
Hans-Kristian Arntzen099f3072017-03-06 15:21:00 +01006099
Robert Konrad45270f62016-08-14 16:21:43 +02006100 uint32_t pass_count = 0;
6101 do
6102 {
Hans-Kristian Arntzen1d13a3e2022-01-17 14:12:01 +01006103 reset(pass_count);
Robert Konrad45270f62016-08-14 16:21:43 +02006104
6105 // Move constructor for this type is broken on GCC 4.9 ...
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006106 buffer.reset();
Robert Konrad45270f62016-08-14 16:21:43 +02006107
6108 emit_header();
6109 emit_resources();
6110
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02006111 emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
Robert Konrad80fcf552016-08-14 21:33:32 +02006112 emit_hlsl_entry_point();
Robert Konrad45270f62016-08-14 16:21:43 +02006113
6114 pass_count++;
Hans-Kristian Arntzen317144a2019-04-05 12:06:10 +02006115 } while (is_forcing_recompilation());
Robert Konrad45270f62016-08-14 16:21:43 +02006116
Hans-Kristian Arntzen4427cb92017-11-13 13:49:11 +01006117 // Entry point in HLSL is always main() for the time being.
6118 get_entry_point().name = "main";
6119
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02006120 return buffer.str();
Robert Konrad45270f62016-08-14 16:21:43 +02006121}
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +02006122
6123void CompilerHLSL::emit_block_hints(const SPIRBlock &block)
6124{
6125 switch (block.hint)
6126 {
6127 case SPIRBlock::HintFlatten:
6128 statement("[flatten]");
6129 break;
6130 case SPIRBlock::HintDontFlatten:
6131 statement("[branch]");
6132 break;
6133 case SPIRBlock::HintUnroll:
6134 statement("[unroll]");
6135 break;
6136 case SPIRBlock::HintDontUnroll:
6137 statement("[loop]");
6138 break;
6139 default:
6140 break;
6141 }
6142}
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01006143
6144string CompilerHLSL::get_unique_identifier()
6145{
6146 return join("_", unique_identifier_count++, "ident");
6147}
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01006148
6149void CompilerHLSL::add_hlsl_resource_binding(const HLSLResourceBinding &binding)
6150{
6151 StageSetBinding tuple = { binding.stage, binding.desc_set, binding.binding };
6152 resource_bindings[tuple] = { binding, false };
6153}
6154
6155bool CompilerHLSL::is_hlsl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) const
6156{
6157 StageSetBinding tuple = { model, desc_set, binding };
6158 auto itr = resource_bindings.find(tuple);
6159 return itr != end(resource_bindings) && itr->second.second;
6160}
Asuka55dfbea2020-04-17 22:46:06 +08006161
6162CompilerHLSL::BitcastType CompilerHLSL::get_bitcast_type(uint32_t result_type, uint32_t op0)
6163{
6164 auto &rslt_type = get<SPIRType>(result_type);
6165 auto &expr_type = expression_type(op0);
6166
6167 if (rslt_type.basetype == SPIRType::BaseType::UInt64 && expr_type.basetype == SPIRType::BaseType::UInt &&
6168 expr_type.vecsize == 2)
6169 return BitcastType::TypePackUint2x32;
6170 else if (rslt_type.basetype == SPIRType::BaseType::UInt && rslt_type.vecsize == 2 &&
6171 expr_type.basetype == SPIRType::BaseType::UInt64)
6172 return BitcastType::TypeUnpackUint64;
6173
6174 return BitcastType::TypeNormal;
6175}
Bryan Bernhart17bccc92020-05-27 13:08:15 -07006176
Bryan Bernhart32bead82020-05-28 10:21:41 -07006177bool CompilerHLSL::is_hlsl_force_storage_buffer_as_uav(ID id) const
Bryan Bernhart17bccc92020-05-27 13:08:15 -07006178{
6179 if (hlsl_options.force_storage_buffer_as_uav)
6180 {
6181 return true;
Bryan Bernhart32bead82020-05-28 10:21:41 -07006182 }
6183
6184 const uint32_t desc_set = get_decoration(id, spv::DecorationDescriptorSet);
6185 const uint32_t binding = get_decoration(id, spv::DecorationBinding);
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02006186
6187 return (force_uav_buffer_bindings.find({ desc_set, binding }) != force_uav_buffer_bindings.end());
Bryan Bernhart17bccc92020-05-27 13:08:15 -07006188}
6189
Bryan Bernhart32bead82020-05-28 10:21:41 -07006190void CompilerHLSL::set_hlsl_force_storage_buffer_as_uav(uint32_t desc_set, uint32_t binding)
Bryan Bernhart17bccc92020-05-27 13:08:15 -07006191{
Bryan Bernhart32bead82020-05-28 10:21:41 -07006192 SetBindingPair pair = { desc_set, binding };
6193 force_uav_buffer_bindings.insert(pair);
6194}
Tomek Ponitkaba58f782020-07-23 19:09:43 +02006195
6196bool CompilerHLSL::builtin_translates_to_nonarray(spv::BuiltIn builtin) const
6197{
6198 return (builtin == BuiltInSampleMask);
6199}