diff --git a/src/dawn_native/opengl/ShaderModuleGL.cpp b/src/dawn_native/opengl/ShaderModuleGL.cpp index cc225491bd..0bd18952e4 100644 --- a/src/dawn_native/opengl/ShaderModuleGL.cpp +++ b/src/dawn_native/opengl/ShaderModuleGL.cpp @@ -84,7 +84,14 @@ namespace dawn_native { namespace opengl { // Tint currently does not support emitting GLSL, so when provided a Tint program need to // generate SPIRV and SPIRV-Cross reflection data to be used in this backend. if (GetDevice()->IsToggleEnabled(Toggle::UseTintGenerator)) { - tint::writer::spirv::Generator generator(GetTintProgram()); + tint::transform::Manager transformManager; + transformManager.append(std::make_unique()); + + tint::Program program; + DAWN_TRY_ASSIGN( + program, RunTransforms(&transformManager, GetTintProgram(), CompilationMessages())); + + tint::writer::spirv::Generator generator(&program); if (!generator.Generate()) { std::ostringstream errorStream; errorStream << "Generator: " << generator.error() << std::endl; diff --git a/src/tests/end2end/ShaderTests.cpp b/src/tests/end2end/ShaderTests.cpp index 089a285f0e..08e6efdd2f 100644 --- a/src/tests/end2end/ShaderTests.cpp +++ b/src/tests/end2end/ShaderTests.cpp @@ -14,7 +14,7 @@ #include "tests/DawnTest.h" -#include "tests/DawnTest.h" +#include "utils/ComboRenderPipelineDescriptor.h" #include "utils/WGPUHelpers.h" #include @@ -95,6 +95,219 @@ I am an invalid shader and should never pass validation! ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, shader.c_str())); } +// Tests that shaders using non-struct function parameters and return values for shader stage I/O +// can compile and link successfully. +TEST_P(ShaderTests, WGSLParamIO) { + std::string vertexShader = R"( +[[stage(vertex)]] +fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4 { + let pos : array, 3> = array, 3>( + vec2(-1.0, 1.0), + vec2( 1.0, 1.0), + vec2( 0.0, -1.0)); + return vec4(pos[VertexIndex], 0.0, 1.0); +})"; + wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, vertexShader.c_str()); + + std::string fragmentShader = R"( +[[stage(fragment)]] +fn main([[builtin(frag_coord)]] fragCoord : vec4) -> [[location(0)]] vec4 { + return vec4(fragCoord.xy, 0.0, 1.0); +})"; + wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fragmentShader.c_str()); + + utils::ComboRenderPipelineDescriptor2 rpDesc; + rpDesc.vertex.module = vsModule; + rpDesc.cFragment.module = fsModule; + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&rpDesc); +} + +// Tests that a vertex shader using struct function parameters and return values for shader stage +// I/O can compile and link successfully against a fragement shader using compatible non-struct I/O. +TEST_P(ShaderTests, WGSLMixedStructParamIO) { + std::string vertexShader = R"( +struct VertexIn { + [[location(0)]] position : vec3; + [[location(1)]] color : vec4; +}; + +struct VertexOut { + [[location(0)]] color : vec4; + [[builtin(position)]] position : vec4; +}; + +[[stage(vertex)]] +fn main(input : VertexIn) -> VertexOut { + var output : VertexOut; + output.position = vec4(input.position, 1.0); + output.color = input.color; + return output; +})"; + wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, vertexShader.c_str()); + + std::string fragmentShader = R"( +[[stage(fragment)]] +fn main([[location(0)]] color : vec4) -> [[location(0)]] vec4 { + return color; +})"; + wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fragmentShader.c_str()); + + utils::ComboRenderPipelineDescriptor2 rpDesc; + rpDesc.vertex.module = vsModule; + rpDesc.cFragment.module = fsModule; + rpDesc.vertex.bufferCount = 1; + rpDesc.cBuffers[0].attributeCount = 2; + rpDesc.cBuffers[0].arrayStride = 28; + rpDesc.cAttributes[0].shaderLocation = 0; + rpDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x3; + rpDesc.cAttributes[1].shaderLocation = 1; + rpDesc.cAttributes[1].format = wgpu::VertexFormat::Float32x4; + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&rpDesc); +} + +// Tests that shaders using struct function parameters and return values for shader stage I/O +// can compile and link successfully. +TEST_P(ShaderTests, WGSLStructIO) { + std::string vertexShader = R"( +struct VertexIn { + [[location(0)]] position : vec3; + [[location(1)]] color : vec4; +}; + +struct VertexOut { + [[location(0)]] color : vec4; + [[builtin(position)]] position : vec4; +}; + +[[stage(vertex)]] +fn main(input : VertexIn) -> VertexOut { + var output : VertexOut; + output.position = vec4(input.position, 1.0); + output.color = input.color; + return output; +})"; + wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, vertexShader.c_str()); + + std::string fragmentShader = R"( +struct FragmentIn { + [[location(0)]] color : vec4; + [[builtin(frag_coord)]] fragCoord : vec4; +}; + +[[stage(fragment)]] +fn main(input : FragmentIn) -> [[location(0)]] vec4 { + return input.color * input.fragCoord; +})"; + wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fragmentShader.c_str()); + + utils::ComboRenderPipelineDescriptor2 rpDesc; + rpDesc.vertex.module = vsModule; + rpDesc.cFragment.module = fsModule; + rpDesc.vertex.bufferCount = 1; + rpDesc.cBuffers[0].attributeCount = 2; + rpDesc.cBuffers[0].arrayStride = 28; + rpDesc.cAttributes[0].shaderLocation = 0; + rpDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x3; + rpDesc.cAttributes[1].shaderLocation = 1; + rpDesc.cAttributes[1].format = wgpu::VertexFormat::Float32x4; + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&rpDesc); +} + +// Tests that shaders I/O structs that us compatible locations but are not sorted by hand can link. +TEST_P(ShaderTests, WGSLUnsortedStructIO) { + // TODO(tint:710): Tint has a known issue with sorting structs in HLSL. + DAWN_SKIP_TEST_IF(IsD3D12()); + + std::string vertexShader = R"( +struct VertexIn { + [[location(0)]] position : vec3; + [[location(1)]] color : vec4; +}; + +struct VertexOut { + [[builtin(position)]] position : vec4; + [[location(0)]] color : vec4; +}; + +[[stage(vertex)]] +fn main(input : VertexIn) -> VertexOut { + var output : VertexOut; + output.position = vec4(input.position, 1.0); + output.color = input.color; + return output; +})"; + wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, vertexShader.c_str()); + + std::string fragmentShader = R"( +struct FragmentIn { + [[location(0)]] color : vec4; + [[builtin(frag_coord)]] fragCoord : vec4; +}; + +[[stage(fragment)]] +fn main(input : FragmentIn) -> [[location(0)]] vec4 { + return input.color * input.fragCoord; +})"; + wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fragmentShader.c_str()); + + utils::ComboRenderPipelineDescriptor2 rpDesc; + rpDesc.vertex.module = vsModule; + rpDesc.cFragment.module = fsModule; + rpDesc.vertex.bufferCount = 1; + rpDesc.cBuffers[0].attributeCount = 2; + rpDesc.cBuffers[0].arrayStride = 28; + rpDesc.cAttributes[0].shaderLocation = 0; + rpDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x3; + rpDesc.cAttributes[1].shaderLocation = 1; + rpDesc.cAttributes[1].format = wgpu::VertexFormat::Float32x4; + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&rpDesc); +} + +// Tests that shaders I/O structs can be shared between vertex and fragment shaders. +TEST_P(ShaderTests, WGSLSharedStructIO) { + // TODO(tint:714): Not yet implemeneted in tint yet, but intended to work. + DAWN_SKIP_TEST_IF(IsD3D12() || IsVulkan() || IsMetal() || IsOpenGL() || IsOpenGLES()); + + std::string shader = R"( +struct VertexIn { + [[location(0)]] position : vec3; + [[location(1)]] color : vec4; +}; + +struct VertexOut { + [[location(0)]] color : vec4; + [[builtin(position)]] position : vec4; +}; + +[[stage(vertex)]] +fn vertexMain(input : VertexIn) -> VertexOut { + var output : VertexOut; + output.position = vec4(input.position, 1.0); + output.color = input.color; + return output; +} + +[[stage(fragment)]] +fn fragmentMain(input : VertexOut) -> [[location(0)]] vec4 { + return input.color; +})"; + wgpu::ShaderModule shaderModule = utils::CreateShaderModule(device, shader.c_str()); + + utils::ComboRenderPipelineDescriptor2 rpDesc; + rpDesc.vertex.module = shaderModule; + rpDesc.vertex.entryPoint = "vertexMain"; + rpDesc.cFragment.module = shaderModule; + rpDesc.cFragment.entryPoint = "fragmentMain"; + rpDesc.vertex.bufferCount = 1; + rpDesc.cBuffers[0].attributeCount = 2; + rpDesc.cBuffers[0].arrayStride = 28; + rpDesc.cAttributes[0].shaderLocation = 0; + rpDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x3; + rpDesc.cAttributes[1].shaderLocation = 1; + rpDesc.cAttributes[1].format = wgpu::VertexFormat::Float32x4; + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&rpDesc); +} + DAWN_INSTANTIATE_TEST(ShaderTests, D3D12Backend(), MetalBackend(),