• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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