blob: 2eeadbbbab9b88653c1d27fbfd5cb17c2251f370 [file] [log] [blame]
Jiawei Shao0bc168e2019-03-28 14:18:11 +00001// Copyright 2019 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 "common/Assert.h"
18#include "utils/ComboRenderPipelineDescriptor.h"
Corentin Wallez04863c42019-10-25 11:36:47 +000019#include "utils/WGPUHelpers.h"
Jiawei Shao0bc168e2019-03-28 14:18:11 +000020
21class MultisampledRenderingTest : public DawnTest {
22 protected:
Austin Eng40dc5d32020-05-15 22:06:35 +000023 void SetUp() override {
24 DawnTest::SetUp();
Jiawei Shao0bc168e2019-03-28 14:18:11 +000025
26 InitTexturesForTest();
27 }
28
29 void InitTexturesForTest() {
Corentin Wallez6b087812020-10-27 15:35:56 +000030 mMultisampledColorTexture = CreateTextureForRenderAttachment(kColorFormat, kSampleCount);
Austin Eng8f9523e2020-06-19 16:21:33 +000031 mMultisampledColorView = mMultisampledColorTexture.CreateView();
Corentin Wallez6b087812020-10-27 15:35:56 +000032 mResolveTexture = CreateTextureForRenderAttachment(kColorFormat, 1);
Kai Ninomiya4078ed82019-08-27 17:56:23 +000033 mResolveView = mResolveTexture.CreateView();
Austin Eng342c6ea2019-04-18 18:28:48 +000034
Corentin Wallez6b087812020-10-27 15:35:56 +000035 mDepthStencilTexture = CreateTextureForRenderAttachment(kDepthStencilFormat, kSampleCount);
Kai Ninomiya4078ed82019-08-27 17:56:23 +000036 mDepthStencilView = mDepthStencilTexture.CreateView();
Jiawei Shao0bc168e2019-03-28 14:18:11 +000037 }
38
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +000039 wgpu::RenderPipeline CreateRenderPipelineWithOneOutputForTest(
40 bool testDepth,
Tomek Ponitkaab04da42020-07-29 11:44:41 +000041 uint32_t sampleMask = 0xFFFFFFFF,
42 bool alphaToCoverageEnabled = false,
43 bool flipTriangle = false) {
Corentin Wallez57090602021-03-19 09:48:11 +000044 const char* kFsOneOutputWithDepth = R"(
45 [[block]] struct U {
46 color : vec4<f32>;
47 depth : f32;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000048 };
Corentin Wallez57090602021-03-19 09:48:11 +000049 [[group(0), binding(0)]] var<uniform> uBuffer : U;
50 [[location(0)]] var<out> FragColor : vec4<f32>;
51 [[builtin(frag_depth)]] var<out> FragDepth : f32;
52
53 [[stage(fragment)]] fn main() -> void {
54 FragColor = uBuffer.color;
55 FragDepth = uBuffer.depth;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000056 })";
57
Corentin Wallez57090602021-03-19 09:48:11 +000058 const char* kFsOneOutputWithoutDepth = R"(
59 [[block]] struct U {
60 color : vec4<f32>;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000061 };
Corentin Wallez57090602021-03-19 09:48:11 +000062 [[group(0), binding(0)]] var<uniform> uBuffer : U;
63 [[location(0)]] var<out> FragColor : vec4<f32>;
64
65 [[stage(fragment)]] fn main() -> void {
66 FragColor = uBuffer.color;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000067 })";
68
69 const char* fs = testDepth ? kFsOneOutputWithDepth : kFsOneOutputWithoutDepth;
70
Tomek Ponitkaab04da42020-07-29 11:44:41 +000071 return CreateRenderPipelineForTest(fs, 1, testDepth, sampleMask, alphaToCoverageEnabled,
72 flipTriangle);
Jiawei Shao0bc168e2019-03-28 14:18:11 +000073 }
74
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +000075 wgpu::RenderPipeline CreateRenderPipelineWithTwoOutputsForTest(
Tomek Ponitkaab04da42020-07-29 11:44:41 +000076 uint32_t sampleMask = 0xFFFFFFFF,
77 bool alphaToCoverageEnabled = false) {
Corentin Wallez57090602021-03-19 09:48:11 +000078 const char* kFsTwoOutputs = R"(
79 [[block]] struct U {
80 color0 : vec4<f32>;
81 color1 : vec4<f32>;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000082 };
Corentin Wallez57090602021-03-19 09:48:11 +000083 [[group(0), binding(0)]] var<uniform> uBuffer : U;
84 [[location(0)]] var<out> FragColor0 : vec4<f32>;
85 [[location(1)]] var<out> FragColor1 : vec4<f32>;
86
87 [[stage(fragment)]] fn main() -> void {
88 FragColor0 = uBuffer.color0;
89 FragColor1 = uBuffer.color1;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000090 })";
91
Tomek Ponitkaab04da42020-07-29 11:44:41 +000092 return CreateRenderPipelineForTest(kFsTwoOutputs, 2, false, sampleMask,
93 alphaToCoverageEnabled);
Jiawei Shao0bc168e2019-03-28 14:18:11 +000094 }
95
Corentin Wallez6b087812020-10-27 15:35:56 +000096 wgpu::Texture CreateTextureForRenderAttachment(wgpu::TextureFormat format,
Jiawei Shao0bc168e2019-03-28 14:18:11 +000097 uint32_t sampleCount,
98 uint32_t mipLevelCount = 1,
99 uint32_t arrayLayerCount = 1) {
Corentin Wallezcab352c2019-10-28 13:27:36 +0000100 wgpu::TextureDescriptor descriptor;
101 descriptor.dimension = wgpu::TextureDimension::e2D;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000102 descriptor.size.width = kWidth << (mipLevelCount - 1);
103 descriptor.size.height = kHeight << (mipLevelCount - 1);
shrekshaob00de7f2021-03-22 21:12:36 +0000104 descriptor.size.depthOrArrayLayers = arrayLayerCount;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000105 descriptor.sampleCount = sampleCount;
106 descriptor.format = format;
107 descriptor.mipLevelCount = mipLevelCount;
Corentin Wallez6b087812020-10-27 15:35:56 +0000108 descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000109 return device.CreateTexture(&descriptor);
110 }
111
Corentin Wallezcab352c2019-10-28 13:27:36 +0000112 void EncodeRenderPassForTest(wgpu::CommandEncoder commandEncoder,
113 const wgpu::RenderPassDescriptor& renderPass,
114 const wgpu::RenderPipeline& pipeline,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000115 const float* uniformData,
116 uint32_t uniformDataSize) {
Corentin Wallezcab352c2019-10-28 13:27:36 +0000117 wgpu::Buffer uniformBuffer = utils::CreateBufferFromData(
118 device, uniformData, uniformDataSize, wgpu::BufferUsage::Uniform);
Austin Eng476a14a2019-12-03 21:18:05 +0000119 wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
Corentin Wallezcab352c2019-10-28 13:27:36 +0000120 {{0, uniformBuffer, 0, uniformDataSize}});
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000121
Corentin Wallezcab352c2019-10-28 13:27:36 +0000122 wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000123 renderPassEncoder.SetPipeline(pipeline);
Corentin Wallez70c8c102019-10-09 16:08:42 +0000124 renderPassEncoder.SetBindGroup(0, bindGroup);
Corentin Wallez67b1ad72020-03-31 16:21:35 +0000125 renderPassEncoder.Draw(3);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000126 renderPassEncoder.EndPass();
127 }
128
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000129 void EncodeRenderPassForTest(wgpu::CommandEncoder commandEncoder,
130 const wgpu::RenderPassDescriptor& renderPass,
131 const wgpu::RenderPipeline& pipeline,
132 const wgpu::Color& color) {
Brandon Jones670858d2020-09-22 16:51:36 +0000133 const float uniformData[4] = {static_cast<float>(color.r), static_cast<float>(color.g),
134 static_cast<float>(color.b), static_cast<float>(color.a)};
135 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, uniformData,
136 sizeof(float) * 4);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000137 }
138
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000139 utils::ComboRenderPassDescriptor CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000140 std::initializer_list<wgpu::TextureView> colorViews,
141 std::initializer_list<wgpu::TextureView> resolveTargetViews,
142 wgpu::LoadOp colorLoadOp,
143 wgpu::LoadOp depthStencilLoadOp,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000144 bool hasDepthStencilAttachment) {
145 ASSERT(colorViews.size() == resolveTargetViews.size());
146
Corentin Wallezcab352c2019-10-28 13:27:36 +0000147 constexpr wgpu::Color kClearColor = {0.0f, 0.0f, 0.0f, 0.0f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000148 constexpr float kClearDepth = 1.0f;
149
150 utils::ComboRenderPassDescriptor renderPass(colorViews);
151 uint32_t i = 0;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000152 for (const wgpu::TextureView& resolveTargetView : resolveTargetViews) {
Corentin Walleza838c7d2019-09-20 22:59:47 +0000153 renderPass.cColorAttachments[i].loadOp = colorLoadOp;
154 renderPass.cColorAttachments[i].clearColor = kClearColor;
155 renderPass.cColorAttachments[i].resolveTarget = resolveTargetView;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000156 ++i;
157 }
158
159 renderPass.cDepthStencilAttachmentInfo.clearDepth = kClearDepth;
160 renderPass.cDepthStencilAttachmentInfo.depthLoadOp = depthStencilLoadOp;
161
162 if (hasDepthStencilAttachment) {
Austin Eng342c6ea2019-04-18 18:28:48 +0000163 renderPass.cDepthStencilAttachmentInfo.attachment = mDepthStencilView;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000164 renderPass.depthStencilAttachment = &renderPass.cDepthStencilAttachmentInfo;
165 }
166
167 return renderPass;
168 }
169
Corentin Wallezcab352c2019-10-28 13:27:36 +0000170 void VerifyResolveTarget(const wgpu::Color& inputColor,
171 wgpu::Texture resolveTexture,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000172 uint32_t mipmapLevel = 0,
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000173 uint32_t arrayLayer = 0,
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000174 const float msaaCoverage = 0.5f) {
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000175 // In this test we only check the pixel in the middle of the texture.
176 constexpr uint32_t kMiddleX = (kWidth - 1) / 2;
177 constexpr uint32_t kMiddleY = (kHeight - 1) / 2;
178
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000179 RGBA8 expectedColor = ExpectedMSAAColor(inputColor, msaaCoverage);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000180 EXPECT_TEXTURE_RGBA8_EQ(&expectedColor, resolveTexture, kMiddleX, kMiddleY, 1, 1,
181 mipmapLevel, arrayLayer);
182 }
183
184 constexpr static uint32_t kWidth = 3;
185 constexpr static uint32_t kHeight = 3;
186 constexpr static uint32_t kSampleCount = 4;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000187 constexpr static wgpu::TextureFormat kColorFormat = wgpu::TextureFormat::RGBA8Unorm;
188 constexpr static wgpu::TextureFormat kDepthStencilFormat =
189 wgpu::TextureFormat::Depth24PlusStencil8;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000190
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000191 constexpr static uint32_t kFirstSampleMaskBit = 0x00000001;
192 constexpr static uint32_t kSecondSampleMaskBit = 0x00000002;
193 constexpr static uint32_t kThirdSampleMaskBit = 0x00000004;
194 constexpr static uint32_t kFourthSampleMaskBit = 0x00000008;
195
Austin Eng8f9523e2020-06-19 16:21:33 +0000196 wgpu::Texture mMultisampledColorTexture;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000197 wgpu::TextureView mMultisampledColorView;
198 wgpu::Texture mResolveTexture;
199 wgpu::TextureView mResolveView;
200 wgpu::Texture mDepthStencilTexture;
201 wgpu::TextureView mDepthStencilView;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000202
Corentin Wallezcab352c2019-10-28 13:27:36 +0000203 wgpu::RenderPipeline CreateRenderPipelineForTest(const char* fs,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000204 uint32_t numColorAttachments,
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000205 bool hasDepthStencilAttachment,
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000206 uint32_t sampleMask = 0xFFFFFFFF,
207 bool alphaToCoverageEnabled = false,
208 bool flipTriangle = false) {
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000209 utils::ComboRenderPipelineDescriptor2 pipelineDescriptor;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000210
211 // Draw a bottom-right triangle. In standard 4xMSAA pattern, for the pixels on diagonal,
212 // only two of the samples will be touched.
Corentin Wallez57090602021-03-19 09:48:11 +0000213 const char* vs = R"(
214 [[builtin(position)]] var<out> Position : vec4<f32>;
215 [[builtin(vertex_index)]] var<in> VertexIndex : u32;
216
217 [[stage(vertex)]] fn main() -> void {
218 const pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
219 vec2<f32>(-1.0, 1.0),
220 vec2<f32>( 1.0, 1.0),
221 vec2<f32>( 1.0, -1.0)
222 );
223 Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000224 })";
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000225
226 // Draw a bottom-left triangle.
Corentin Wallez57090602021-03-19 09:48:11 +0000227 const char* vsFlipped = R"(
228 [[builtin(position)]] var<out> Position : vec4<f32>;
229 [[builtin(vertex_index)]] var<in> VertexIndex : u32;
230
231 [[stage(vertex)]] fn main() -> void {
232 const pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
233 vec2<f32>(-1.0, 1.0),
234 vec2<f32>( 1.0, 1.0),
235 vec2<f32>(-1.0, -1.0)
236 );
237 Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000238 })";
239
240 if (flipTriangle) {
Corentin Wallez57090602021-03-19 09:48:11 +0000241 pipelineDescriptor.vertex.module = utils::CreateShaderModuleFromWGSL(device, vsFlipped);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000242 } else {
Corentin Wallez57090602021-03-19 09:48:11 +0000243 pipelineDescriptor.vertex.module = utils::CreateShaderModuleFromWGSL(device, vs);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000244 }
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000245
Corentin Wallez57090602021-03-19 09:48:11 +0000246 pipelineDescriptor.cFragment.module = utils::CreateShaderModuleFromWGSL(device, fs);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000247
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000248 if (hasDepthStencilAttachment) {
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000249 wgpu::DepthStencilState* depthStencil =
250 pipelineDescriptor.EnableDepthStencil(kDepthStencilFormat);
251 depthStencil->depthWriteEnabled = true;
252 depthStencil->depthCompare = wgpu::CompareFunction::Less;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000253 }
254
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000255 pipelineDescriptor.multisample.count = kSampleCount;
256 pipelineDescriptor.multisample.mask = sampleMask;
257 pipelineDescriptor.multisample.alphaToCoverageEnabled = alphaToCoverageEnabled;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000258
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000259 pipelineDescriptor.cFragment.targetCount = numColorAttachments;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000260 for (uint32_t i = 0; i < numColorAttachments; ++i) {
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000261 pipelineDescriptor.cTargets[i].format = kColorFormat;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000262 }
263
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000264 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&pipelineDescriptor);
Austin Eng476a14a2019-12-03 21:18:05 +0000265 return pipeline;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000266 }
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000267
Brandon Jones670858d2020-09-22 16:51:36 +0000268 RGBA8 ExpectedMSAAColor(const wgpu::Color color, const double msaaCoverage) {
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000269 RGBA8 result;
Brandon Jones670858d2020-09-22 16:51:36 +0000270 result.r = static_cast<uint8_t>(std::min(255.0, 256 * color.r * msaaCoverage));
271 result.g = static_cast<uint8_t>(std::min(255.0, 256 * color.g * msaaCoverage));
272 result.b = static_cast<uint8_t>(std::min(255.0, 256 * color.b * msaaCoverage));
273 result.a = static_cast<uint8_t>(std::min(255.0, 256 * color.a * msaaCoverage));
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000274 return result;
275 }
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000276};
277
278// Test using one multisampled color attachment with resolve target can render correctly.
279TEST_P(MultisampledRenderingTest, ResolveInto2DTexture) {
280 constexpr bool kTestDepth = false;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000281 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000282
Corentin Wallezcab352c2019-10-28 13:27:36 +0000283 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000284
Kai Ninomiya57fcd172021-01-28 07:03:45 +0000285 // storeOp should not affect the result in the resolve target.
286 for (wgpu::StoreOp storeOp : {wgpu::StoreOp::Store, wgpu::StoreOp::Clear}) {
287 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
288
289 // Draw a green triangle.
290 {
291 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
292 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
293 kTestDepth);
294 renderPass.cColorAttachments[0].storeOp = storeOp;
295 std::array<float, 4> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a};
296 constexpr uint32_t kSize = sizeof(kUniformData);
297 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(),
298 kSize);
299 }
300
301 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
302 queue.Submit(1, &commandBuffer);
303
304 VerifyResolveTarget(kGreen, mResolveTexture);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000305 }
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000306}
307
Austin Eng8f9523e2020-06-19 16:21:33 +0000308// Test that a single-layer multisampled texture view can be created and resolved from.
309TEST_P(MultisampledRenderingTest, ResolveFromSingleLayerArrayInto2DTexture) {
310 constexpr bool kTestDepth = false;
311 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
312 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
313
314 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Austin Eng8f9523e2020-06-19 16:21:33 +0000315
316 // Draw a green triangle.
317 {
318 wgpu::TextureViewDescriptor desc = {};
319 desc.dimension = wgpu::TextureViewDimension::e2DArray;
320 desc.arrayLayerCount = 1;
321
322 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
323 {mMultisampledColorTexture.CreateView(&desc)}, {mResolveView}, wgpu::LoadOp::Clear,
324 wgpu::LoadOp::Clear, kTestDepth);
325
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000326 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Austin Eng8f9523e2020-06-19 16:21:33 +0000327 }
328
329 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
330 queue.Submit(1, &commandBuffer);
331
332 VerifyResolveTarget(kGreen, mResolveTexture);
333}
334
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000335// Test multisampled rendering with depth test works correctly.
336TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTest) {
337 constexpr bool kTestDepth = true;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000338 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
339 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000340
Corentin Wallezcab352c2019-10-28 13:27:36 +0000341 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
342 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000343
344 // In first render pass we draw a green triangle with depth value == 0.2f.
345 {
Corentin Wallezcab352c2019-10-28 13:27:36 +0000346 utils::ComboRenderPassDescriptor renderPass =
347 CreateComboRenderPassDescriptorForTest({mMultisampledColorView}, {mResolveView},
348 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, true);
Kai Ninomiya2afea0c2020-07-10 20:33:08 +0000349 std::array<float, 5> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a, // Color
350 0.2f}; // depth
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000351 constexpr uint32_t kSize = sizeof(kUniformData);
352 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
353 }
354
355 // In second render pass we draw a red triangle with depth value == 0.5f.
356 // This red triangle should not be displayed because it is behind the green one that is drawn in
357 // the last render pass.
358 {
359 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000360 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000361 kTestDepth);
362
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000363 std::array<float, 5> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color
Kai Ninomiya2afea0c2020-07-10 20:33:08 +0000364 0.5f}; // depth
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000365 constexpr uint32_t kSize = sizeof(kUniformData);
366 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
367 }
368
Corentin Wallezcab352c2019-10-28 13:27:36 +0000369 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000370 queue.Submit(1, &commandBuffer);
371
372 // The color of the pixel in the middle of mResolveTexture should be green if MSAA resolve runs
373 // correctly with depth test.
374 VerifyResolveTarget(kGreen, mResolveTexture);
375}
376
377// Test rendering into a multisampled color attachment and doing MSAA resolve in another render pass
378// works correctly.
379TEST_P(MultisampledRenderingTest, ResolveInAnotherRenderPass) {
380 constexpr bool kTestDepth = false;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000381 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
382 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000383
Corentin Wallezcab352c2019-10-28 13:27:36 +0000384 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000385
386 // In first render pass we draw a green triangle and do not set the resolve target.
387 {
388 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000389 {mMultisampledColorView}, {nullptr}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000390 kTestDepth);
391
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000392 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000393 }
394
395 // In second render pass we ony do MSAA resolve with no draw call.
396 {
397 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000398 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000399 kTestDepth);
400
Corentin Wallezcab352c2019-10-28 13:27:36 +0000401 wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000402 renderPassEncoder.EndPass();
403 }
404
Corentin Wallezcab352c2019-10-28 13:27:36 +0000405 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000406 queue.Submit(1, &commandBuffer);
407
408 VerifyResolveTarget(kGreen, mResolveTexture);
409}
410
411// Test doing MSAA resolve into multiple resolve targets works correctly.
412TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargets) {
Bryan Bernhart1f162292020-07-27 19:50:21 +0000413 // TODO(dawn:462): Investigate backend validation failure.
414 DAWN_SKIP_TEST_IF(IsD3D12() && IsNvidia() && IsBackendValidationEnabled());
415
Corentin Wallezcab352c2019-10-28 13:27:36 +0000416 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000417 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
418 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000419 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000420
Corentin Wallezcab352c2019-10-28 13:27:36 +0000421 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
422 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithTwoOutputsForTest();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000423
Corentin Wallezcab352c2019-10-28 13:27:36 +0000424 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
425 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000426 constexpr bool kTestDepth = false;
427
428 // Draw a red triangle to the first color attachment, and a blue triangle to the second color
429 // attachment, and do MSAA resolve on two render targets in one render pass.
430 {
431 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
432 {mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2},
Corentin Wallezcab352c2019-10-28 13:27:36 +0000433 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000434
Brandon Jones670858d2020-09-22 16:51:36 +0000435 std::array<float, 8> kUniformData = {
436 static_cast<float>(kRed.r), static_cast<float>(kRed.g),
437 static_cast<float>(kRed.b), static_cast<float>(kRed.a),
438 static_cast<float>(kGreen.r), static_cast<float>(kGreen.g),
439 static_cast<float>(kGreen.b), static_cast<float>(kGreen.a)};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000440 constexpr uint32_t kSize = sizeof(kUniformData);
Brandon Jones670858d2020-09-22 16:51:36 +0000441
442 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000443 }
444
Corentin Wallezcab352c2019-10-28 13:27:36 +0000445 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000446 queue.Submit(1, &commandBuffer);
447
448 VerifyResolveTarget(kRed, mResolveTexture);
449 VerifyResolveTarget(kGreen, resolveTexture2);
450}
451
Jiawei Shao865cad82019-04-09 08:04:59 +0000452// Test doing MSAA resolve on one multisampled texture twice works correctly.
453TEST_P(MultisampledRenderingTest, ResolveOneMultisampledTextureTwice) {
454 constexpr bool kTestDepth = false;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000455 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
456 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Jiawei Shao865cad82019-04-09 08:04:59 +0000457
Corentin Wallezcab352c2019-10-28 13:27:36 +0000458 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Jiawei Shao865cad82019-04-09 08:04:59 +0000459
Corentin Wallez6b087812020-10-27 15:35:56 +0000460 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Jiawei Shao865cad82019-04-09 08:04:59 +0000461
462 // In first render pass we draw a green triangle and specify mResolveView as the resolve target.
463 {
464 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000465 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
Jiawei Shao865cad82019-04-09 08:04:59 +0000466 kTestDepth);
467
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000468 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Jiawei Shao865cad82019-04-09 08:04:59 +0000469 }
470
471 // In second render pass we do MSAA resolve into resolveTexture2.
472 {
Corentin Wallezcab352c2019-10-28 13:27:36 +0000473 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
Jiawei Shao865cad82019-04-09 08:04:59 +0000474 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000475 {mMultisampledColorView}, {resolveView2}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
Jiawei Shao865cad82019-04-09 08:04:59 +0000476 kTestDepth);
477
Corentin Wallezcab352c2019-10-28 13:27:36 +0000478 wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass);
Jiawei Shao865cad82019-04-09 08:04:59 +0000479 renderPassEncoder.EndPass();
480 }
481
Corentin Wallezcab352c2019-10-28 13:27:36 +0000482 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao865cad82019-04-09 08:04:59 +0000483 queue.Submit(1, &commandBuffer);
484
485 VerifyResolveTarget(kGreen, mResolveTexture);
486 VerifyResolveTarget(kGreen, resolveTexture2);
487}
488
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000489// Test using a layer of a 2D texture as resolve target works correctly.
490TEST_P(MultisampledRenderingTest, ResolveIntoOneMipmapLevelOf2DTexture) {
Bryan Bernhart1f162292020-07-27 19:50:21 +0000491 // TODO(dawn:462): Investigate backend validation failure.
Jiawei Shao2fe73352020-11-30 13:50:49 +0000492 DAWN_SKIP_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
Bryan Bernhart1f162292020-07-27 19:50:21 +0000493
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000494 constexpr uint32_t kBaseMipLevel = 2;
495
Corentin Wallezcab352c2019-10-28 13:27:36 +0000496 wgpu::TextureViewDescriptor textureViewDescriptor;
497 textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000498 textureViewDescriptor.format = kColorFormat;
499 textureViewDescriptor.baseArrayLayer = 0;
500 textureViewDescriptor.arrayLayerCount = 1;
501 textureViewDescriptor.mipLevelCount = 1;
502 textureViewDescriptor.baseMipLevel = kBaseMipLevel;
503
Corentin Wallezcab352c2019-10-28 13:27:36 +0000504 wgpu::Texture resolveTexture =
Corentin Wallez6b087812020-10-27 15:35:56 +0000505 CreateTextureForRenderAttachment(kColorFormat, 1, kBaseMipLevel + 1, 1);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000506 wgpu::TextureView resolveView = resolveTexture.CreateView(&textureViewDescriptor);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000507
Corentin Wallezcab352c2019-10-28 13:27:36 +0000508 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
509 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000510 constexpr bool kTestDepth = false;
511
512 // Draw a green triangle and do MSAA resolve.
513 {
514 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000515 {mMultisampledColorView}, {resolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000516 kTestDepth);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000517 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000518 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000519 }
520
Corentin Wallezcab352c2019-10-28 13:27:36 +0000521 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000522 queue.Submit(1, &commandBuffer);
523
524 VerifyResolveTarget(kGreen, resolveTexture, kBaseMipLevel, 0);
525}
526
527// Test using a level or a layer of a 2D array texture as resolve target works correctly.
528TEST_P(MultisampledRenderingTest, ResolveInto2DArrayTexture) {
Bryan Bernhart1f162292020-07-27 19:50:21 +0000529 // TODO(dawn:462): Investigate backend validation failure.
Jiawei Shao2fe73352020-11-30 13:50:49 +0000530 DAWN_SKIP_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
Bryan Bernhart1f162292020-07-27 19:50:21 +0000531
Corentin Wallezcab352c2019-10-28 13:27:36 +0000532 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000533 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000534
Corentin Wallezcab352c2019-10-28 13:27:36 +0000535 wgpu::TextureViewDescriptor baseTextureViewDescriptor;
536 baseTextureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000537 baseTextureViewDescriptor.format = kColorFormat;
538 baseTextureViewDescriptor.arrayLayerCount = 1;
539 baseTextureViewDescriptor.mipLevelCount = 1;
540
541 // Create resolveTexture1 with only 1 mipmap level.
542 constexpr uint32_t kBaseArrayLayer1 = 2;
543 constexpr uint32_t kBaseMipLevel1 = 0;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000544 wgpu::Texture resolveTexture1 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000545 CreateTextureForRenderAttachment(kColorFormat, 1, kBaseMipLevel1 + 1, kBaseArrayLayer1 + 1);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000546 wgpu::TextureViewDescriptor resolveViewDescriptor1 = baseTextureViewDescriptor;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000547 resolveViewDescriptor1.baseArrayLayer = kBaseArrayLayer1;
548 resolveViewDescriptor1.baseMipLevel = kBaseMipLevel1;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000549 wgpu::TextureView resolveView1 = resolveTexture1.CreateView(&resolveViewDescriptor1);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000550
551 // Create resolveTexture2 with (kBaseMipLevel2 + 1) mipmap levels and resolve into its last
552 // mipmap level.
553 constexpr uint32_t kBaseArrayLayer2 = 5;
554 constexpr uint32_t kBaseMipLevel2 = 3;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000555 wgpu::Texture resolveTexture2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000556 CreateTextureForRenderAttachment(kColorFormat, 1, kBaseMipLevel2 + 1, kBaseArrayLayer2 + 1);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000557 wgpu::TextureViewDescriptor resolveViewDescriptor2 = baseTextureViewDescriptor;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000558 resolveViewDescriptor2.baseArrayLayer = kBaseArrayLayer2;
559 resolveViewDescriptor2.baseMipLevel = kBaseMipLevel2;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000560 wgpu::TextureView resolveView2 = resolveTexture2.CreateView(&resolveViewDescriptor2);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000561
Corentin Wallezcab352c2019-10-28 13:27:36 +0000562 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
563 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithTwoOutputsForTest();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000564
Corentin Wallezcab352c2019-10-28 13:27:36 +0000565 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
566 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000567 constexpr bool kTestDepth = false;
568
569 // Draw a red triangle to the first color attachment, and a green triangle to the second color
570 // attachment, and do MSAA resolve on two render targets in one render pass.
571 {
572 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
573 {mMultisampledColorView, multisampledColorView2}, {resolveView1, resolveView2},
Corentin Wallezcab352c2019-10-28 13:27:36 +0000574 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000575
Kai Ninomiya2afea0c2020-07-10 20:33:08 +0000576 std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1
577 kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000578 constexpr uint32_t kSize = sizeof(kUniformData);
579 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
580 }
581
Corentin Wallezcab352c2019-10-28 13:27:36 +0000582 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000583 queue.Submit(1, &commandBuffer);
584
585 VerifyResolveTarget(kRed, resolveTexture1, kBaseMipLevel1, kBaseArrayLayer1);
586 VerifyResolveTarget(kGreen, resolveTexture2, kBaseMipLevel2, kBaseArrayLayer2);
587}
588
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000589// Test using one multisampled color attachment with resolve target can render correctly
590// with a non-default sample mask.
591TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithSampleMask) {
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000592 constexpr bool kTestDepth = false;
593 // The second and third samples are included,
594 // only the second one is covered by the triangle.
595 constexpr uint32_t kSampleMask = kSecondSampleMaskBit | kThirdSampleMaskBit;
596 constexpr float kMSAACoverage = 0.25f;
597 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
598 wgpu::RenderPipeline pipeline =
599 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMask);
600
601 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000602
603 // Draw a green triangle.
604 {
605 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
606 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
607 kTestDepth);
608
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000609 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000610 }
611
612 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
613 queue.Submit(1, &commandBuffer);
614
615 VerifyResolveTarget(kGreen, mResolveTexture, 0, 0, kMSAACoverage);
616}
617
618// Test using one multisampled color attachment with resolve target can render correctly
619// with the final sample mask empty.
620TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithEmptyFinalSampleMask) {
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000621 constexpr bool kTestDepth = false;
622 // The third and fourth samples are included,
623 // none of which is covered by the triangle.
624 constexpr uint32_t kSampleMask = kThirdSampleMaskBit | kFourthSampleMaskBit;
625 constexpr float kMSAACoverage = 0.00f;
626 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
627 wgpu::RenderPipeline pipeline =
628 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMask);
629
630 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000631
632 // Draw a green triangle.
633 {
634 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
635 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
636 kTestDepth);
637
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000638 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000639 }
640
641 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
642 queue.Submit(1, &commandBuffer);
643
644 VerifyResolveTarget(kGreen, mResolveTexture, 0, 0, kMSAACoverage);
645}
646
647// Test doing MSAA resolve into multiple resolve targets works correctly with a non-default sample
648// mask.
649TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargetsWithSampleMask) {
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000650 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000651 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
652 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000653 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
654
655 // The first and fourth samples are included,
656 // only the first one is covered by the triangle.
657 constexpr uint32_t kSampleMask = kFirstSampleMaskBit | kFourthSampleMaskBit;
658 constexpr float kMSAACoverage = 0.25f;
659
660 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
661 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithTwoOutputsForTest(kSampleMask);
662
663 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
664 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
665 constexpr bool kTestDepth = false;
666
667 // Draw a red triangle to the first color attachment, and a blue triangle to the second color
668 // attachment, and do MSAA resolve on two render targets in one render pass.
669 {
670 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
671 {mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2},
672 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
673
Brandon Jones670858d2020-09-22 16:51:36 +0000674 std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1
675 kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000676 constexpr uint32_t kSize = sizeof(kUniformData);
Brandon Jones670858d2020-09-22 16:51:36 +0000677 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000678 }
679
680 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
681 queue.Submit(1, &commandBuffer);
682
683 VerifyResolveTarget(kRed, mResolveTexture, 0, 0, kMSAACoverage);
684 VerifyResolveTarget(kGreen, resolveTexture2, 0, 0, kMSAACoverage);
685}
686
687// Test multisampled rendering with depth test works correctly with a non-default sample mask.
688TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTestAndSampleMask) {
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000689 constexpr bool kTestDepth = true;
690 // The second sample is included in the first render pass and it's covered by the triangle.
691 constexpr uint32_t kSampleMaskGreen = kSecondSampleMaskBit;
692 // The first and second samples are included in the second render pass,
693 // both are covered by the triangle.
694 constexpr uint32_t kSampleMaskRed = kFirstSampleMaskBit | kSecondSampleMaskBit;
695 constexpr float kMSAACoverage = 0.50f;
696
697 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
698 wgpu::RenderPipeline pipelineGreen =
699 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMaskGreen);
700 wgpu::RenderPipeline pipelineRed =
701 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMaskRed);
702
703 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
704 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
705
706 // In first render pass we draw a green triangle with depth value == 0.2f.
707 // We will only write to the second sample.
708 {
709 utils::ComboRenderPassDescriptor renderPass =
710 CreateComboRenderPassDescriptorForTest({mMultisampledColorView}, {mResolveView},
711 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, true);
712 std::array<float, 5> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a, // Color
713 0.2f}; // depth
714 constexpr uint32_t kSize = sizeof(kUniformData);
715 EncodeRenderPassForTest(commandEncoder, renderPass, pipelineGreen, kUniformData.data(),
716 kSize);
717 }
718
719 // In second render pass we draw a red triangle with depth value == 0.5f.
720 // We will only write to the first sample, since the second one is red with a smaller depth
721 // value.
722 {
723 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
724 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
725 kTestDepth);
726
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000727 std::array<float, 5> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000728 0.5f}; // depth
729 constexpr uint32_t kSize = sizeof(kUniformData);
730 EncodeRenderPassForTest(commandEncoder, renderPass, pipelineRed, kUniformData.data(),
731 kSize);
732 }
733
734 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
735 queue.Submit(1, &commandBuffer);
736
737 constexpr wgpu::Color kHalfGreenHalfRed = {(kGreen.r + kRed.r) / 2.0, (kGreen.g + kRed.g) / 2.0,
738 (kGreen.b + kRed.b) / 2.0,
739 (kGreen.a + kRed.a) / 2.0};
740
741 // The color of the pixel in the middle of mResolveTexture should be half green and half
742 // red if MSAA resolve runs correctly with depth test.
743 VerifyResolveTarget(kHalfGreenHalfRed, mResolveTexture, 0, 0, kMSAACoverage);
744}
745
746// Test using one multisampled color attachment with resolve target can render correctly
747// with non-default sample mask and shader-output mask.
748TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithSampleMaskAndShaderOutputMask) {
Ben Claytonbbc23542021-02-24 12:50:00 +0000749 // TODO(github.com/KhronosGroup/SPIRV-Cross/issues/1626): SPIRV-Cross produces bad GLSL for
750 // unsigned SampleMask builtins
751 DAWN_SKIP_TEST_IF(HasToggleEnabled("use_tint_generator") && (IsOpenGL() || IsOpenGLES()));
Austin Eng30805552020-12-08 16:49:34 +0000752
Stephen White725e03b2021-02-10 15:14:05 +0000753 // TODO(crbug.com/dawn/673): Work around or enforce via validation that sample variables are not
Stephen White02fd17c2021-02-10 02:28:17 +0000754 // supported on some platforms.
755 DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_sample_variables"));
Stephen White0315c432021-01-26 12:53:38 +0000756
Corentin Wallez57090602021-03-19 09:48:11 +0000757 // TODO(cwallez@chromium.org): Fails on Metal / D3D12 because SPIRV-Cross produces bad shaders
758 // for the SPIR-V outputted by Tint. Reenable once we use Tint's MSL / HLSL generators.
759 DAWN_SKIP_TEST_IF(IsD3D12() || IsMetal());
760
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000761 constexpr bool kTestDepth = false;
762 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
763
764 // The second and third samples are included in the shader-output mask.
765 // The first and third samples are included in the sample mask.
766 // Since we're now looking at a fully covered pixel, the rasterization mask
767 // includes all the samples.
768 // Thus the final mask includes only the third sample.
769 constexpr float kMSAACoverage = 0.25f;
770 constexpr uint32_t kSampleMask = kFirstSampleMaskBit | kThirdSampleMaskBit;
Corentin Wallez57090602021-03-19 09:48:11 +0000771 const char* fs = R"(
772 [[block]] struct U {
773 color : vec4<f32>;
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000774 };
Corentin Wallez57090602021-03-19 09:48:11 +0000775 [[group(0), binding(0)]] var<uniform> uBuffer : U;
776 [[location(0)]] var<out> FragColor : vec4<f32>;
777 [[builtin(sample_mask_out)]] var<out> SampleMask : u32;
778
779 [[stage(fragment)]] fn main() -> void {
780 FragColor = uBuffer.color;
781 SampleMask = 6u;
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000782 })";
783
784 wgpu::RenderPipeline pipeline = CreateRenderPipelineForTest(fs, 1, false, kSampleMask);
785 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000786
787 // Draw a green triangle.
788 {
789 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
790 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
791 kTestDepth);
792
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000793 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000794 }
795
796 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
797 queue.Submit(1, &commandBuffer);
798
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000799 RGBA8 expectedColor = ExpectedMSAAColor(kGreen, kMSAACoverage);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000800 EXPECT_TEXTURE_RGBA8_EQ(&expectedColor, mResolveTexture, 1, 0, 1, 1, 0, 0);
801}
802
803// Test doing MSAA resolve into multiple resolve targets works correctly with a non-default
804// shader-output mask.
805TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargetsWithShaderOutputMask) {
Ben Claytonbbc23542021-02-24 12:50:00 +0000806 // TODO(github.com/KhronosGroup/SPIRV-Cross/issues/1626): SPIRV-Cross produces bad GLSL for
807 // unsigned SampleMask builtins
808 DAWN_SKIP_TEST_IF(HasToggleEnabled("use_tint_generator") && (IsOpenGL() || IsOpenGLES()));
Austin Eng30805552020-12-08 16:49:34 +0000809
Stephen White725e03b2021-02-10 15:14:05 +0000810 // TODO(crbug.com/dawn/673): Work around or enforce via validation that sample variables are not
Stephen White02fd17c2021-02-10 02:28:17 +0000811 // supported on some platforms.
812 DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_sample_variables"));
Stephen White0315c432021-01-26 12:53:38 +0000813
Corentin Wallez57090602021-03-19 09:48:11 +0000814 // TODO(cwallez@chromium.org): Fails on Metal / D3D12 because SPIRV-Cross produces bad shaders
815 // for the SPIR-V outputted by Tint. Reenable once we use Tint's MSL / HLSL generators.
816 DAWN_SKIP_TEST_IF(IsD3D12() || IsMetal());
817
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000818 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000819 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
820 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000821 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
822
823 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
824 // The second and third samples are included in the shader-output mask,
825 // only the first one is covered by the triangle.
826 constexpr float kMSAACoverage = 0.25f;
Corentin Wallez57090602021-03-19 09:48:11 +0000827 const char* fs = R"(
828 [[block]] struct U {
829 color0 : vec4<f32>;
830 color1 : vec4<f32>;
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000831 };
Corentin Wallez57090602021-03-19 09:48:11 +0000832 [[group(0), binding(0)]] var<uniform> uBuffer : U;
833 [[location(0)]] var<out> FragColor0 : vec4<f32>;
834 [[location(1)]] var<out> FragColor1 : vec4<f32>;
835 [[builtin(sample_mask_out)]] var<out> SampleMask : u32;
836
837 [[stage(fragment)]] fn main() -> void {
838 FragColor0 = uBuffer.color0;
839 FragColor1 = uBuffer.color1;
840 SampleMask = 6u;
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000841 })";
842
843 wgpu::RenderPipeline pipeline = CreateRenderPipelineForTest(fs, 2, false);
844 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
845 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
846 constexpr bool kTestDepth = false;
847
848 // Draw a red triangle to the first color attachment, and a blue triangle to the second color
849 // attachment, and do MSAA resolve on two render targets in one render pass.
850 {
851 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
852 {mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2},
853 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
854
Brandon Jones670858d2020-09-22 16:51:36 +0000855 std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1
856 kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000857 constexpr uint32_t kSize = sizeof(kUniformData);
Brandon Jones670858d2020-09-22 16:51:36 +0000858 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000859 }
860
861 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
862 queue.Submit(1, &commandBuffer);
863
864 VerifyResolveTarget(kRed, mResolveTexture, 0, 0, kMSAACoverage);
865 VerifyResolveTarget(kGreen, resolveTexture2, 0, 0, kMSAACoverage);
866}
867
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000868// Test using one multisampled color attachment with resolve target can render correctly
869// with alphaToCoverageEnabled.
870TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithAlphaToCoverage) {
871 constexpr bool kTestDepth = false;
872 constexpr uint32_t kSampleMask = 0xFFFFFFFF;
873 constexpr bool kAlphaToCoverageEnabled = true;
874
875 // Setting alpha <= 0 must result in alpha-to-coverage mask being empty.
876 // Setting alpha = 0.5f should result in alpha-to-coverage mask including half the samples,
877 // but this is not guaranteed by the spec. The Metal spec seems to guarantee that this is
878 // indeed the case.
879 // Setting alpha >= 1 must result in alpha-to-coverage mask being full.
880 for (float alpha : {-1.0f, 0.0f, 0.5f, 1.0f, 2.0f}) {
881 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
882 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(
883 kTestDepth, kSampleMask, kAlphaToCoverageEnabled);
884
885 const wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, alpha};
886
887 // Draw a green triangle.
888 {
889 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
890 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
891 kTestDepth);
892
893 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
894 }
895
896 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
897 queue.Submit(1, &commandBuffer);
898
899 // For alpha = {0, 0.5, 1} we expect msaaCoverage to correspond to the value of alpha.
900 float msaaCoverage = alpha;
901 if (alpha < 0.0f) {
902 msaaCoverage = 0.0f;
903 }
904 if (alpha > 1.0f) {
905 msaaCoverage = 1.0f;
906 }
907
908 RGBA8 expectedColor = ExpectedMSAAColor(kGreen, msaaCoverage);
909 EXPECT_TEXTURE_RGBA8_EQ(&expectedColor, mResolveTexture, 1, 0, 1, 1, 0, 0);
910 }
911}
912
913// Test doing MSAA resolve into multiple resolve targets works correctly with
914// alphaToCoverage. The alphaToCoverage mask is computed based on the alpha
Corentin Wallez49a1f722021-01-22 19:51:37 +0000915// component of the first color render attachment.
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000916TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargetsWithAlphaToCoverage) {
917 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000918 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
919 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000920 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
921 constexpr uint32_t kSampleMask = 0xFFFFFFFF;
922 constexpr float kMSAACoverage = 0.50f;
923 constexpr bool kAlphaToCoverageEnabled = true;
924
925 // The alpha-to-coverage mask should not depend on the alpha component of the
Corentin Wallez49a1f722021-01-22 19:51:37 +0000926 // second color render attachment.
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000927 // We test alpha = 0.51f and 0.99f instead of 0.50f and 1.00f because there are some rounding
928 // differences on QuadroP400 devices in that case.
929 for (float alpha : {0.0f, 0.51f, 0.99f}) {
930 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
931 wgpu::RenderPipeline pipeline =
932 CreateRenderPipelineWithTwoOutputsForTest(kSampleMask, kAlphaToCoverageEnabled);
933
934 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.51f};
935 const wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, alpha};
936 constexpr bool kTestDepth = false;
937
938 // Draw a red triangle to the first color attachment, and a blue triangle to the second
939 // color attachment, and do MSAA resolve on two render targets in one render pass.
940 {
941 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
942 {mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2},
943 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
944
Brandon Jones670858d2020-09-22 16:51:36 +0000945 std::array<float, 8> kUniformData = {
946 static_cast<float>(kRed.r), static_cast<float>(kRed.g),
947 static_cast<float>(kRed.b), static_cast<float>(kRed.a),
948 static_cast<float>(kGreen.r), static_cast<float>(kGreen.g),
949 static_cast<float>(kGreen.b), static_cast<float>(kGreen.a)};
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000950 constexpr uint32_t kSize = sizeof(kUniformData);
Brandon Jones670858d2020-09-22 16:51:36 +0000951 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(),
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000952 kSize);
953 }
954
955 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
956 queue.Submit(1, &commandBuffer);
957
958 // Alpha to coverage affects both the color outputs, but the mask is computed
959 // using only the first one.
960 RGBA8 expectedRed = ExpectedMSAAColor(kRed, kMSAACoverage);
961 RGBA8 expectedGreen = ExpectedMSAAColor(kGreen, kMSAACoverage);
962 EXPECT_TEXTURE_RGBA8_EQ(&expectedRed, mResolveTexture, 1, 0, 1, 1, 0, 0);
963 EXPECT_TEXTURE_RGBA8_EQ(&expectedGreen, resolveTexture2, 1, 0, 1, 1, 0, 0);
964 }
965}
966
967// Test multisampled rendering with depth test works correctly with alphaToCoverage.
968TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTestAndAlphaToCoverage) {
Corentin Wallez6298b632020-10-19 18:35:39 +0000969 // This test fails because Swiftshader is off-by-one with its ((a+b)/2 + (c+d)/2)/2 fast resolve
970 // algorithm.
Stephen White0315c432021-01-26 12:53:38 +0000971 DAWN_SKIP_TEST_IF(IsSwiftshader() || IsANGLE());
Corentin Wallez6298b632020-10-19 18:35:39 +0000972
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000973 constexpr bool kTestDepth = true;
974 constexpr uint32_t kSampleMask = 0xFFFFFFFF;
975
976 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
977 wgpu::RenderPipeline pipelineGreen =
978 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMask, true);
979 wgpu::RenderPipeline pipelineRed =
980 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMask, false);
981
982 // We test alpha = 0.51f and 0.81f instead of 0.50f and 0.80f because there are some
983 // rounding differences on QuadroP400 devices in that case.
984 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.51f};
985 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.81f};
986
987 // In first render pass we draw a green triangle with depth value == 0.2f.
988 // We will only write to half the samples since the alphaToCoverage mode
989 // is enabled for that render pass.
990 {
991 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
992 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
993 kTestDepth);
994 std::array<float, 5> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a, // Color
995 0.2f}; // depth
996 constexpr uint32_t kSize = sizeof(kUniformData);
997 EncodeRenderPassForTest(commandEncoder, renderPass, pipelineGreen, kUniformData.data(),
998 kSize);
999 }
1000
1001 // In second render pass we draw a red triangle with depth value == 0.5f.
1002 // We will write to all the samples since the alphaToCoverageMode is diabled for
1003 // that render pass.
1004 {
1005 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
1006 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
1007 kTestDepth);
1008
1009 std::array<float, 5> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color
1010 0.5f}; // depth
1011 constexpr uint32_t kSize = sizeof(kUniformData);
1012 EncodeRenderPassForTest(commandEncoder, renderPass, pipelineRed, kUniformData.data(),
1013 kSize);
1014 }
1015
1016 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
1017 queue.Submit(1, &commandBuffer);
1018
1019 constexpr wgpu::Color kHalfGreenHalfRed = {(kGreen.r + kRed.r) / 2.0, (kGreen.g + kRed.g) / 2.0,
1020 (kGreen.b + kRed.b) / 2.0,
1021 (kGreen.a + kRed.a) / 2.0};
1022 RGBA8 expectedColor = ExpectedMSAAColor(kHalfGreenHalfRed, 1.0f);
1023
1024 EXPECT_TEXTURE_RGBA8_EQ(&expectedColor, mResolveTexture, 1, 0, 1, 1, 0, 0);
1025}
1026
1027// Test using one multisampled color attachment with resolve target can render correctly
1028// with alphaToCoverageEnabled and a sample mask.
1029TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithAlphaToCoverageAndSampleMask) {
Corentin Wallez6298b632020-10-19 18:35:39 +00001030 // This test fails because Swiftshader is off-by-one with its ((a+b)/2 + (c+d)/2)/2 fast resolve
1031 // algorithm.
Stephen White0315c432021-01-26 12:53:38 +00001032 DAWN_SKIP_TEST_IF(IsSwiftshader() || IsANGLE());
Corentin Wallez6298b632020-10-19 18:35:39 +00001033
Tomek Ponitkaab04da42020-07-29 11:44:41 +00001034 // TODO(dawn:491): This doesn't work on Metal, because we're using both the shader-output
1035 // mask (emulting the sampleMask from RenderPipeline) and alpha-to-coverage at the same
1036 // time. See the issue: https://github.com/gpuweb/gpuweb/issues/959.
1037 DAWN_SKIP_TEST_IF(IsMetal());
1038
1039 constexpr bool kTestDepth = false;
1040 constexpr float kMSAACoverage = 0.50f;
1041 constexpr uint32_t kSampleMask = kFirstSampleMaskBit | kThirdSampleMaskBit;
1042 constexpr bool kAlphaToCoverageEnabled = true;
1043
1044 // For those values of alpha we expect the proportion of samples to be covered
1045 // to correspond to the value of alpha.
1046 // We're assuming in the case of alpha = 0.50f that the implementation
1047 // dependendent algorithm will choose exactly one of the first and third samples.
1048 for (float alpha : {0.0f, 0.50f, 1.00f}) {
1049 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
1050 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(
1051 kTestDepth, kSampleMask, kAlphaToCoverageEnabled);
1052
1053 const wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, alpha - 0.01f};
1054
1055 // Draw a green triangle.
1056 {
1057 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
1058 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
1059 kTestDepth);
1060
1061 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
1062 }
1063
1064 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
1065 queue.Submit(1, &commandBuffer);
1066
1067 RGBA8 expectedColor = ExpectedMSAAColor(kGreen, kMSAACoverage * alpha);
1068 EXPECT_TEXTURE_RGBA8_EQ(&expectedColor, mResolveTexture, 1, 0, 1, 1, 0, 0);
1069 }
1070}
1071
1072// Test using one multisampled color attachment with resolve target can render correctly
1073// with alphaToCoverageEnabled and a rasterization mask.
1074TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithAlphaToCoverageAndRasterizationMask) {
Corentin Wallez6298b632020-10-19 18:35:39 +00001075 // This test fails because Swiftshader is off-by-one with its ((a+b)/2 + (c+d)/2)/2 fast resolve
1076 // algorithm.
Stephen White0315c432021-01-26 12:53:38 +00001077 DAWN_SKIP_TEST_IF(IsSwiftshader() || IsANGLE());
Corentin Wallez6298b632020-10-19 18:35:39 +00001078
Tomek Ponitkaab04da42020-07-29 11:44:41 +00001079 constexpr bool kTestDepth = false;
1080 constexpr float kMSAACoverage = 0.50f;
1081 constexpr uint32_t kSampleMask = 0xFFFFFFFF;
1082 constexpr bool kAlphaToCoverageEnabled = true;
1083 constexpr bool kFlipTriangle = true;
1084
1085 // For those values of alpha we expect the proportion of samples to be covered
1086 // to correspond to the value of alpha.
1087 // We're assuming in the case of alpha = 0.50f that the implementation
1088 // dependendent algorithm will choose exactly one of the samples covered by the
1089 // triangle.
1090 for (float alpha : {0.0f, 0.50f, 1.00f}) {
1091 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
1092 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(
1093 kTestDepth, kSampleMask, kAlphaToCoverageEnabled, kFlipTriangle);
1094
1095 const wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, alpha - 0.01f};
1096
1097 // Draw a green triangle.
1098 {
1099 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
1100 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
1101 kTestDepth);
1102
1103 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
1104 }
1105
1106 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
1107 queue.Submit(1, &commandBuffer);
1108
1109 VerifyResolveTarget(kGreen, mResolveTexture, 0, 0, kMSAACoverage * alpha);
1110 }
1111}
1112
Jiawei Shao15d4c2e2019-04-26 07:52:57 +00001113DAWN_INSTANTIATE_TEST(MultisampledRenderingTest,
Austin Eng6c1d6462020-02-25 16:23:17 +00001114 D3D12Backend(),
1115 D3D12Backend({}, {"use_d3d12_resource_heap_tier2"}),
1116 D3D12Backend({}, {"use_d3d12_render_pass"}),
1117 MetalBackend(),
1118 OpenGLBackend(),
Stephen Whitef31b78e2020-12-04 15:59:29 +00001119 OpenGLESBackend(),
Austin Eng6c1d6462020-02-25 16:23:17 +00001120 VulkanBackend(),
1121 MetalBackend({"emulate_store_and_msaa_resolve"}),
1122 MetalBackend({"always_resolve_into_zero_level_and_layer"}),
1123 MetalBackend({"always_resolve_into_zero_level_and_layer",
Corentin Wallez84a57752019-12-05 14:02:11 +00001124 "emulate_store_and_msaa_resolve"}));