1 // Copyright 2020 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "common/Math.h"
16 #include "tests/DawnTest.h"
17
18 #include "utils/WGPUHelpers.h"
19
20 class ShaderFloat16Tests : public DawnTest {
21 protected:
GetRequiredFeatures()22 std::vector<const char*> GetRequiredFeatures() override {
23 mIsShaderFloat16Supported = SupportsFeatures({"shader-float16"});
24 if (!mIsShaderFloat16Supported) {
25 return {};
26 }
27
28 return {"shader-float16"};
29 }
30
IsShaderFloat16Supported() const31 bool IsShaderFloat16Supported() const {
32 return mIsShaderFloat16Supported;
33 }
34
35 bool mIsShaderFloat16Supported = false;
36 };
37
38 // Test basic 16bit float arithmetic and 16bit storage features.
39 // TODO(crbug.com/tint/404): Implement float16 in Tint.
TEST_P(ShaderFloat16Tests,DISABLED_Basic16BitFloatFeaturesTest)40 TEST_P(ShaderFloat16Tests, DISABLED_Basic16BitFloatFeaturesTest) {
41 DAWN_TEST_UNSUPPORTED_IF(!IsShaderFloat16Supported());
42 DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsIntel()); // Flaky crashes. crbug.com/dawn/586
43
44 uint16_t uniformData[] = {Float32ToFloat16(1.23), Float32ToFloat16(0.0)}; // 0.0 is a padding.
45 wgpu::Buffer uniformBuffer = utils::CreateBufferFromData(
46 device, &uniformData, sizeof(uniformData), wgpu::BufferUsage::Uniform);
47
48 uint16_t bufferInData[] = {Float32ToFloat16(2.34), Float32ToFloat16(0.0)}; // 0.0 is a padding.
49 wgpu::Buffer bufferIn = utils::CreateBufferFromData(device, &bufferInData, sizeof(bufferInData),
50 wgpu::BufferUsage::Storage);
51
52 wgpu::BufferDescriptor bufferDesc;
53 bufferDesc.size = 2 * sizeof(uint16_t);
54 bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
55 wgpu::Buffer bufferOut = device.CreateBuffer(&bufferDesc);
56
57 // SPIR-V ASM produced by glslang for the following fragment shader:
58 //
59 // #version 450
60 // #extension GL_AMD_gpu_shader_half_float : require
61 //
62 // struct S {
63 // float16_t f;
64 // float16_t padding;
65 // };
66 // layout(std140, set = 0, binding = 0) uniform uniformBuf { S c; };
67 // layout(std140, set = 0, binding = 1) readonly buffer bufA { S a; };
68 // layout(std140, set = 0, binding = 2) buffer bufB { S b; };
69 //
70 // void main() {
71 // b.f = a.f + c.f;
72 // }
73
74 wgpu::ShaderModule module = utils::CreateShaderModuleFromASM(device, R"(
75 ; SPIR-V
76 ; Version: 1.0
77 ; Generator: Khronos Glslang Reference Front End; 10
78 ; Bound: 26
79 ; Schema: 0
80 OpCapability Shader
81 OpCapability Float16
82 OpCapability StorageBuffer16BitAccess
83 OpCapability UniformAndStorageBuffer16BitAccess
84 OpExtension "SPV_KHR_16bit_storage"
85 %1 = OpExtInstImport "GLSL.std.450"
86 OpMemoryModel Logical GLSL450
87 OpEntryPoint GLCompute %main "main"
88 OpExecutionMode %main LocalSize 1 1 1
89 OpSource GLSL 450
90 OpSourceExtension "GL_AMD_gpu_shader_half_float"
91 OpName %main "main"
92 OpName %S "S"
93 OpMemberName %S 0 "f"
94 OpMemberName %S 1 "padding"
95 OpName %bufB "bufB"
96 OpMemberName %bufB 0 "b"
97 OpName %_ ""
98 OpName %bufA "bufA"
99 OpMemberName %bufA 0 "a"
100 OpName %__0 ""
101 OpName %uniformBuf "uniformBuf"
102 OpMemberName %uniformBuf 0 "c"
103 OpName %__1 ""
104 OpMemberDecorate %S 0 Offset 0
105 OpMemberDecorate %S 1 Offset 2
106 OpMemberDecorate %bufB 0 Offset 0
107 OpDecorate %bufB BufferBlock
108 OpDecorate %_ DescriptorSet 0
109 OpDecorate %_ Binding 2
110 OpMemberDecorate %bufA 0 NonWritable
111 OpMemberDecorate %bufA 0 Offset 0
112 OpDecorate %bufA BufferBlock
113 OpDecorate %__0 DescriptorSet 0
114 OpDecorate %__0 Binding 1
115 OpMemberDecorate %uniformBuf 0 Offset 0
116 OpDecorate %uniformBuf Block
117 OpDecorate %__1 DescriptorSet 0
118 OpDecorate %__1 Binding 0
119 %void = OpTypeVoid
120 %3 = OpTypeFunction %void
121 %half = OpTypeFloat 16
122 %S = OpTypeStruct %half %half
123 %bufB = OpTypeStruct %S
124 %_ptr_Uniform_bufB = OpTypePointer Uniform %bufB
125 %_ = OpVariable %_ptr_Uniform_bufB Uniform
126 %int = OpTypeInt 32 1
127 %int_0 = OpConstant %int 0
128 %bufA = OpTypeStruct %S
129 %_ptr_Uniform_bufA = OpTypePointer Uniform %bufA
130 %__0 = OpVariable %_ptr_Uniform_bufA Uniform
131 %_ptr_Uniform_half = OpTypePointer Uniform %half
132 %uniformBuf = OpTypeStruct %S
133 %_ptr_Uniform_uniformBuf = OpTypePointer Uniform %uniformBuf
134 %__1 = OpVariable %_ptr_Uniform_uniformBuf Uniform
135 %main = OpFunction %void None %3
136 %5 = OpLabel
137 %17 = OpAccessChain %_ptr_Uniform_half %__0 %int_0 %int_0
138 %18 = OpLoad %half %17
139 %22 = OpAccessChain %_ptr_Uniform_half %__1 %int_0 %int_0
140 %23 = OpLoad %half %22
141 %24 = OpFAdd %half %18 %23
142 %25 = OpAccessChain %_ptr_Uniform_half %_ %int_0 %int_0
143 OpStore %25 %24
144 OpReturn
145 OpFunctionEnd
146 )");
147
148 wgpu::ComputePipelineDescriptor csDesc;
149 csDesc.compute.module = module;
150 csDesc.compute.entryPoint = "main";
151 wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&csDesc);
152
153 wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
154 {
155 {0, uniformBuffer, 0, sizeof(uniformData)},
156 {1, bufferIn, 0, sizeof(bufferInData)},
157 {2, bufferOut},
158 });
159
160 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
161 wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
162 pass.SetPipeline(pipeline);
163 pass.SetBindGroup(0, bindGroup);
164 pass.Dispatch(1);
165 pass.EndPass();
166 wgpu::CommandBuffer commands = encoder.Finish();
167 queue.Submit(1, &commands);
168
169 uint16_t expected[] = {Float32ToFloat16(3.57), Float32ToFloat16(0.0)}; // 0.0 is a padding.
170
171 EXPECT_BUFFER_U16_RANGE_EQ(expected, bufferOut, 0, 2);
172 }
173
174 DAWN_INSTANTIATE_TEST(ShaderFloat16Tests,
175 D3D12Backend(),
176 MetalBackend(),
177 OpenGLBackend(),
178 OpenGLESBackend(),
179 VulkanBackend());
180