| // Copyright 2020 The Dawn Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "common/Math.h" | |
| #include "tests/DawnTest.h" | |
| #include "utils/WGPUHelpers.h" | |
| class ShaderFloat16Tests : public DawnTest { | |
| protected: | |
| std::vector<const char*> GetRequiredFeatures() override { | |
| mIsShaderFloat16Supported = SupportsFeatures({"shader-float16"}); | |
| if (!mIsShaderFloat16Supported) { | |
| return {}; | |
| } | |
| return {"shader-float16"}; | |
| } | |
| bool IsShaderFloat16Supported() const { | |
| return mIsShaderFloat16Supported; | |
| } | |
| bool mIsShaderFloat16Supported = false; | |
| }; | |
| // Test basic 16bit float arithmetic and 16bit storage features. | |
| // TODO(crbug.com/tint/404): Implement float16 in Tint. | |
| TEST_P(ShaderFloat16Tests, DISABLED_Basic16BitFloatFeaturesTest) { | |
| DAWN_TEST_UNSUPPORTED_IF(!IsShaderFloat16Supported()); | |
| DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsIntel()); // Flaky crashes. crbug.com/dawn/586 | |
| uint16_t uniformData[] = {Float32ToFloat16(1.23), Float32ToFloat16(0.0)}; // 0.0 is a padding. | |
| wgpu::Buffer uniformBuffer = utils::CreateBufferFromData( | |
| device, &uniformData, sizeof(uniformData), wgpu::BufferUsage::Uniform); | |
| uint16_t bufferInData[] = {Float32ToFloat16(2.34), Float32ToFloat16(0.0)}; // 0.0 is a padding. | |
| wgpu::Buffer bufferIn = utils::CreateBufferFromData(device, &bufferInData, sizeof(bufferInData), | |
| wgpu::BufferUsage::Storage); | |
| wgpu::BufferDescriptor bufferDesc; | |
| bufferDesc.size = 2 * sizeof(uint16_t); | |
| bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc; | |
| wgpu::Buffer bufferOut = device.CreateBuffer(&bufferDesc); | |
| // SPIR-V ASM produced by glslang for the following fragment shader: | |
| // | |
| // #version 450 | |
| // #extension GL_AMD_gpu_shader_half_float : require | |
| // | |
| // struct S { | |
| // float16_t f; | |
| // float16_t padding; | |
| // }; | |
| // layout(std140, set = 0, binding = 0) uniform uniformBuf { S c; }; | |
| // layout(std140, set = 0, binding = 1) readonly buffer bufA { S a; }; | |
| // layout(std140, set = 0, binding = 2) buffer bufB { S b; }; | |
| // | |
| // void main() { | |
| // b.f = a.f + c.f; | |
| // } | |
| wgpu::ShaderModule module = utils::CreateShaderModuleFromASM(device, R"( | |
| ; SPIR-V | |
| ; Version: 1.0 | |
| ; Generator: Khronos Glslang Reference Front End; 10 | |
| ; Bound: 26 | |
| ; Schema: 0 | |
| OpCapability Shader | |
| OpCapability Float16 | |
| OpCapability StorageBuffer16BitAccess | |
| OpCapability UniformAndStorageBuffer16BitAccess | |
| OpExtension "SPV_KHR_16bit_storage" | |
| %1 = OpExtInstImport "GLSL.std.450" | |
| OpMemoryModel Logical GLSL450 | |
| OpEntryPoint GLCompute %main "main" | |
| OpExecutionMode %main LocalSize 1 1 1 | |
| OpSource GLSL 450 | |
| OpSourceExtension "GL_AMD_gpu_shader_half_float" | |
| OpName %main "main" | |
| OpName %S "S" | |
| OpMemberName %S 0 "f" | |
| OpMemberName %S 1 "padding" | |
| OpName %bufB "bufB" | |
| OpMemberName %bufB 0 "b" | |
| OpName %_ "" | |
| OpName %bufA "bufA" | |
| OpMemberName %bufA 0 "a" | |
| OpName %__0 "" | |
| OpName %uniformBuf "uniformBuf" | |
| OpMemberName %uniformBuf 0 "c" | |
| OpName %__1 "" | |
| OpMemberDecorate %S 0 Offset 0 | |
| OpMemberDecorate %S 1 Offset 2 | |
| OpMemberDecorate %bufB 0 Offset 0 | |
| OpDecorate %bufB BufferBlock | |
| OpDecorate %_ DescriptorSet 0 | |
| OpDecorate %_ Binding 2 | |
| OpMemberDecorate %bufA 0 NonWritable | |
| OpMemberDecorate %bufA 0 Offset 0 | |
| OpDecorate %bufA BufferBlock | |
| OpDecorate %__0 DescriptorSet 0 | |
| OpDecorate %__0 Binding 1 | |
| OpMemberDecorate %uniformBuf 0 Offset 0 | |
| OpDecorate %uniformBuf Block | |
| OpDecorate %__1 DescriptorSet 0 | |
| OpDecorate %__1 Binding 0 | |
| %void = OpTypeVoid | |
| %3 = OpTypeFunction %void | |
| %half = OpTypeFloat 16 | |
| %S = OpTypeStruct %half %half | |
| %bufB = OpTypeStruct %S | |
| %_ptr_Uniform_bufB = OpTypePointer Uniform %bufB | |
| %_ = OpVariable %_ptr_Uniform_bufB Uniform | |
| %int = OpTypeInt 32 1 | |
| %int_0 = OpConstant %int 0 | |
| %bufA = OpTypeStruct %S | |
| %_ptr_Uniform_bufA = OpTypePointer Uniform %bufA | |
| %__0 = OpVariable %_ptr_Uniform_bufA Uniform | |
| %_ptr_Uniform_half = OpTypePointer Uniform %half | |
| %uniformBuf = OpTypeStruct %S | |
| %_ptr_Uniform_uniformBuf = OpTypePointer Uniform %uniformBuf | |
| %__1 = OpVariable %_ptr_Uniform_uniformBuf Uniform | |
| %main = OpFunction %void None %3 | |
| %5 = OpLabel | |
| %17 = OpAccessChain %_ptr_Uniform_half %__0 %int_0 %int_0 | |
| %18 = OpLoad %half %17 | |
| %22 = OpAccessChain %_ptr_Uniform_half %__1 %int_0 %int_0 | |
| %23 = OpLoad %half %22 | |
| %24 = OpFAdd %half %18 %23 | |
| %25 = OpAccessChain %_ptr_Uniform_half %_ %int_0 %int_0 | |
| OpStore %25 %24 | |
| OpReturn | |
| OpFunctionEnd | |
| )"); | |
| wgpu::ComputePipelineDescriptor csDesc; | |
| csDesc.compute.module = module; | |
| csDesc.compute.entryPoint = "main"; | |
| wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&csDesc); | |
| wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), | |
| { | |
| {0, uniformBuffer, 0, sizeof(uniformData)}, | |
| {1, bufferIn, 0, sizeof(bufferInData)}, | |
| {2, bufferOut}, | |
| }); | |
| wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); | |
| wgpu::ComputePassEncoder pass = encoder.BeginComputePass(); | |
| pass.SetPipeline(pipeline); | |
| pass.SetBindGroup(0, bindGroup); | |
| pass.Dispatch(1); | |
| pass.EndPass(); | |
| wgpu::CommandBuffer commands = encoder.Finish(); | |
| queue.Submit(1, &commands); | |
| uint16_t expected[] = {Float32ToFloat16(3.57), Float32ToFloat16(0.0)}; // 0.0 is a padding. | |
| EXPECT_BUFFER_U16_RANGE_EQ(expected, bufferOut, 0, 2); | |
| } | |
| DAWN_INSTANTIATE_TEST(ShaderFloat16Tests, | |
| D3D12Backend(), | |
| MetalBackend(), | |
| OpenGLBackend(), | |
| OpenGLESBackend(), | |
| VulkanBackend()); |