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 "tests/DawnTest.h"
16
17 #include "utils/ComboRenderPipelineDescriptor.h"
18 #include "utils/WGPUHelpers.h"
19
20 class EntryPointTests : public DawnTest {};
21
22 // Test creating a render pipeline from two entryPoints in the same module.
TEST_P(EntryPointTests,FragAndVertexSameModule)23 TEST_P(EntryPointTests, FragAndVertexSameModule) {
24 // TODO(crbug.com/dawn/658): Crashes on bots
25 DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
26 wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
27 [[stage(vertex)]] fn vertex_main() -> [[builtin(position)]] vec4<f32> {
28 return vec4<f32>(0.0, 0.0, 0.0, 1.0);
29 }
30
31 [[stage(fragment)]] fn fragment_main() -> [[location(0)]] vec4<f32> {
32 return vec4<f32>(1.0, 0.0, 0.0, 1.0);
33 }
34 )");
35
36 // Create a point pipeline from the module.
37 utils::ComboRenderPipelineDescriptor desc;
38 desc.vertex.module = module;
39 desc.vertex.entryPoint = "vertex_main";
40 desc.cFragment.module = module;
41 desc.cFragment.entryPoint = "fragment_main";
42 desc.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
43 desc.primitive.topology = wgpu::PrimitiveTopology::PointList;
44 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&desc);
45
46 // Render the point and check that it was rendered.
47 utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
48 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
49 {
50 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
51 pass.SetPipeline(pipeline);
52 pass.Draw(1);
53 pass.EndPass();
54 }
55 wgpu::CommandBuffer commands = encoder.Finish();
56 queue.Submit(1, &commands);
57
58 EXPECT_PIXEL_RGBA8_EQ(RGBA8::kRed, renderPass.color, 0, 0);
59 }
60
61 // Test creating two compute pipelines from the same module.
TEST_P(EntryPointTests,TwoComputeInModule)62 TEST_P(EntryPointTests, TwoComputeInModule) {
63 wgpu::BindGroupLayoutEntry binding = {};
64 binding.binding = 0;
65 binding.buffer.type = wgpu::BufferBindingType::Storage;
66 binding.visibility = wgpu::ShaderStage::Compute;
67
68 wgpu::BindGroupLayoutDescriptor desc = {};
69 desc.entryCount = 1;
70 desc.entries = &binding;
71
72 wgpu::BindGroupLayout bindGroupLayout = device.CreateBindGroupLayout(&desc);
73
74 wgpu::PipelineLayoutDescriptor pipelineLayoutDesc = {};
75 pipelineLayoutDesc.bindGroupLayoutCount = 1;
76 pipelineLayoutDesc.bindGroupLayouts = &bindGroupLayout;
77
78 wgpu::PipelineLayout pipelineLayout = device.CreatePipelineLayout(&pipelineLayoutDesc);
79
80 wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
81 [[block]] struct Data {
82 data : u32;
83 };
84 [[binding(0), group(0)]] var<storage, read_write> data : Data;
85
86 [[stage(compute), workgroup_size(1)]] fn write1() {
87 data.data = 1u;
88 return;
89 }
90
91 [[stage(compute), workgroup_size(1)]] fn write42() {
92 data.data = 42u;
93 return;
94 }
95 )");
96
97 // Create both pipelines from the module.
98 wgpu::ComputePipelineDescriptor pipelineDesc;
99 pipelineDesc.layout = pipelineLayout;
100 pipelineDesc.compute.module = module;
101
102 pipelineDesc.compute.entryPoint = "write1";
103 wgpu::ComputePipeline write1 = device.CreateComputePipeline(&pipelineDesc);
104
105 pipelineDesc.compute.entryPoint = "write42";
106 wgpu::ComputePipeline write42 = device.CreateComputePipeline(&pipelineDesc);
107
108 // Create the bindGroup.
109 wgpu::BufferDescriptor bufferDesc;
110 bufferDesc.size = 4;
111 bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
112 wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
113
114 wgpu::BindGroup group = utils::MakeBindGroup(device, bindGroupLayout, {{0, buffer}});
115
116 // Use the first pipeline and check it wrote 1.
117 {
118 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
119 wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
120 pass.SetPipeline(write1);
121 pass.SetBindGroup(0, group);
122 pass.Dispatch(1);
123 pass.EndPass();
124 wgpu::CommandBuffer commands = encoder.Finish();
125 queue.Submit(1, &commands);
126
127 EXPECT_BUFFER_U32_EQ(1, buffer, 0);
128 }
129
130 // Use the second pipeline and check it wrote 42.
131 {
132 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
133 wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
134 pass.SetPipeline(write42);
135 pass.SetBindGroup(0, group);
136 pass.Dispatch(42);
137 pass.EndPass();
138 wgpu::CommandBuffer commands = encoder.Finish();
139 queue.Submit(1, &commands);
140
141 EXPECT_BUFFER_U32_EQ(42, buffer, 0);
142 }
143 }
144
145 DAWN_INSTANTIATE_TEST(EntryPointTests,
146 D3D12Backend(),
147 MetalBackend(),
148 OpenGLBackend(),
149 OpenGLESBackend(),
150 VulkanBackend());
151