Skip to content

Commit 06c6bae

Browse files
authored
[HLSL] Implement D3DCOLORtoUBYTE4 intrinsic (#122202)
Fixes #99092. 1. Defines the function `D3DCOLORtoUBYTE4` in `clang/lib/Headers/hlsl/hlsl_intrinsics.h`. 2. Implements the function `D3DCOLORtoUBYTE4` as `d3d_color_to_ubyte4` in `clang/lib/Headers/hlsl/hlsl_detail.h` 3. Adds a HLSL codegen test to `clang/test/CodeGenHLSL/builtins/D3DCOLORtoUBYTE4.hlsl` 4. Adds sema tests to `clang/test/SemaHLSL/BuiltIns/D3DCOLORtoUBYTE4-errors.hlsl`
1 parent fbb4697 commit 06c6bae

File tree

4 files changed

+69
-0
lines changed

4 files changed

+69
-0
lines changed

clang/lib/Headers/hlsl/hlsl_detail.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ constexpr enable_if_t<sizeof(U) == sizeof(T), U> bit_cast(T F) {
4141
return __builtin_bit_cast(U, F);
4242
}
4343

44+
constexpr vector<uint, 4> d3d_color_to_ubyte4_impl(vector<float, 4> V) {
45+
// Use the same scaling factor used by FXC, and DXC for DXIL
46+
// (i.e., 255.001953)
47+
// https://github.com/microsoft/DirectXShaderCompiler/blob/070d0d5a2beacef9eeb51037a9b04665716fd6f3/lib/HLSL/HLOperationLower.cpp#L666C1-L697C2
48+
// The DXC implementation refers to a comment on the following stackoverflow
49+
// discussion to justify the scaling factor: "Built-in rounding, necessary
50+
// because of truncation. 0.001953 * 256 = 0.5"
51+
// https://stackoverflow.com/questions/52103720/why-does-d3dcolortoubyte4-multiplies-components-by-255-001953f
52+
return V.zyxw * 255.001953f;
53+
}
54+
4455
template <typename T>
4556
constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
4657
length_impl(T X) {

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,6 +1878,23 @@ half3 cross(half3, half3);
18781878
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_cross)
18791879
float3 cross(float3, float3);
18801880

1881+
//===----------------------------------------------------------------------===//
1882+
// D3DCOLORtoUBYTE4 builtin
1883+
//===----------------------------------------------------------------------===//
1884+
1885+
/// \fn T D3DCOLORtoUBYTE4(T x)
1886+
/// \brief Converts a floating-point, 4D vector set by a D3DCOLOR to a UBYTE4.
1887+
/// \param x [in] The floating-point vector4 to convert.
1888+
///
1889+
/// The return value is the UBYTE4 representation of the \a x parameter.
1890+
///
1891+
/// This function swizzles and scales components of the \a x parameter. Use this
1892+
/// function to compensate for the lack of UBYTE4 support in some hardware.
1893+
1894+
constexpr vector<uint, 4> D3DCOLORtoUBYTE4(vector<float, 4> V) {
1895+
return __detail::d3d_color_to_ubyte4_impl(V);
1896+
}
1897+
18811898
//===----------------------------------------------------------------------===//
18821899
// rcp builtins
18831900
//===----------------------------------------------------------------------===//
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -finclude-default-header -triple \
2+
// RUN: dxil-pc-shadermodel6.3-library %s \
3+
// RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK
4+
5+
// CHECK-LABEL: D3DCOLORtoUBYTE4
6+
int4 test_D3DCOLORtoUBYTE4(float4 p1) {
7+
// CHECK: %[[SCALED:.*]] = fmul [[FMFLAGS:.*]][[FLOAT_TYPE:<4 x float>]] %{{.*}}, splat (float 0x406FE01000000000)
8+
// CHECK: %[[CONVERTED:.*]] = fptoui [[FLOAT_TYPE]] %[[SCALED]] to [[INT_TYPE:<4 x i32>]]
9+
// CHECK: %[[SHUFFLED:.*]] = shufflevector [[INT_TYPE]] %[[CONVERTED]], [[INT_TYPE]] poison, <4 x i32> <i32 2, i32 1, i32 0, i32 3>
10+
// CHECK: ret [[INT_TYPE]] %[[SHUFFLED]]
11+
return D3DCOLORtoUBYTE4(p1);
12+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify
2+
3+
int4 test_too_few_arg() {
4+
return D3DCOLORtoUBYTE4();
5+
// expected-error@-1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
6+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires single argument 'V', but no arguments were provided}}
7+
}
8+
9+
int4 test_too_many_arg(float4 v) {
10+
return D3DCOLORtoUBYTE4(v, v);
11+
// expected-error@-1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
12+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires single argument 'V', but 2 arguments were provided}}
13+
}
14+
15+
int4 float2_arg(float2 v) {
16+
return D3DCOLORtoUBYTE4(v);
17+
// expected-error@-1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
18+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: no known conversion from 'vector<[...], 2>' to 'vector<[...], 4>' for 1st argument}}
19+
}
20+
21+
struct S {
22+
float4 f;
23+
};
24+
25+
int4 struct_arg(S v) {
26+
return D3DCOLORtoUBYTE4(v);
27+
// expected-error@-1 {{no matching function for call to 'D3DCOLORtoUBYTE4'}}
28+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: no known conversion from 'S' to 'vector<float, 4>' (vector of 4 'float' values) for 1st argument}}
29+
}

0 commit comments

Comments
 (0)