blob: 5c1ba179e77d45d0bcf6693fbe28c9c5eabdb033 [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
Ben Clayton47a8cf32021-03-30 13:13:17 +000026 // TODO(crbug.com/dawn/738): Test output is wrong with D3D12 + WARP.
Jiawei Shao44fc6e32021-05-26 01:04:32 +000027 DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP());
Ben Clayton47a8cf32021-03-30 13:13:17 +000028
Jiawei Shao0bc168e2019-03-28 14:18:11 +000029 InitTexturesForTest();
30 }
31
32 void InitTexturesForTest() {
Corentin Wallez6b087812020-10-27 15:35:56 +000033 mMultisampledColorTexture = CreateTextureForRenderAttachment(kColorFormat, kSampleCount);
Austin Eng8f9523e2020-06-19 16:21:33 +000034 mMultisampledColorView = mMultisampledColorTexture.CreateView();
Corentin Wallez6b087812020-10-27 15:35:56 +000035 mResolveTexture = CreateTextureForRenderAttachment(kColorFormat, 1);
Kai Ninomiya4078ed82019-08-27 17:56:23 +000036 mResolveView = mResolveTexture.CreateView();
Austin Eng342c6ea2019-04-18 18:28:48 +000037
Corentin Wallez6b087812020-10-27 15:35:56 +000038 mDepthStencilTexture = CreateTextureForRenderAttachment(kDepthStencilFormat, kSampleCount);
Kai Ninomiya4078ed82019-08-27 17:56:23 +000039 mDepthStencilView = mDepthStencilTexture.CreateView();
Jiawei Shao0bc168e2019-03-28 14:18:11 +000040 }
41
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +000042 wgpu::RenderPipeline CreateRenderPipelineWithOneOutputForTest(
43 bool testDepth,
Tomek Ponitkaab04da42020-07-29 11:44:41 +000044 uint32_t sampleMask = 0xFFFFFFFF,
45 bool alphaToCoverageEnabled = false,
46 bool flipTriangle = false) {
Corentin Wallez57090602021-03-19 09:48:11 +000047 const char* kFsOneOutputWithDepth = R"(
48 [[block]] struct U {
49 color : vec4<f32>;
50 depth : f32;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000051 };
Corentin Wallez57090602021-03-19 09:48:11 +000052 [[group(0), binding(0)]] var<uniform> uBuffer : U;
Corentin Wallez57090602021-03-19 09:48:11 +000053
Brandon Jonese87ea2b2021-04-14 17:05:07 +000054 struct FragmentOut {
55 [[location(0)]] color : vec4<f32>;
56 [[builtin(frag_depth)]] depth : f32;
57 };
58
59 [[stage(fragment)]] fn main() -> FragmentOut {
60 var output : FragmentOut;
61 output.color = uBuffer.color;
62 output.depth = uBuffer.depth;
63 return output;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000064 })";
65
Corentin Wallez57090602021-03-19 09:48:11 +000066 const char* kFsOneOutputWithoutDepth = R"(
67 [[block]] struct U {
68 color : vec4<f32>;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000069 };
Corentin Wallez57090602021-03-19 09:48:11 +000070 [[group(0), binding(0)]] var<uniform> uBuffer : U;
Corentin Wallez57090602021-03-19 09:48:11 +000071
Brandon Jonese87ea2b2021-04-14 17:05:07 +000072 [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
73 return uBuffer.color;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000074 })";
75
76 const char* fs = testDepth ? kFsOneOutputWithDepth : kFsOneOutputWithoutDepth;
77
Tomek Ponitkaab04da42020-07-29 11:44:41 +000078 return CreateRenderPipelineForTest(fs, 1, testDepth, sampleMask, alphaToCoverageEnabled,
79 flipTriangle);
Jiawei Shao0bc168e2019-03-28 14:18:11 +000080 }
81
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +000082 wgpu::RenderPipeline CreateRenderPipelineWithTwoOutputsForTest(
Tomek Ponitkaab04da42020-07-29 11:44:41 +000083 uint32_t sampleMask = 0xFFFFFFFF,
84 bool alphaToCoverageEnabled = false) {
Corentin Wallez57090602021-03-19 09:48:11 +000085 const char* kFsTwoOutputs = R"(
86 [[block]] struct U {
87 color0 : vec4<f32>;
88 color1 : vec4<f32>;
Jiawei Shao0bc168e2019-03-28 14:18:11 +000089 };
Corentin Wallez57090602021-03-19 09:48:11 +000090 [[group(0), binding(0)]] var<uniform> uBuffer : U;
Corentin Wallez57090602021-03-19 09:48:11 +000091
Brandon Jonese87ea2b2021-04-14 17:05:07 +000092 struct FragmentOut {
93 [[location(0)]] color0 : vec4<f32>;
94 [[location(1)]] color1 : vec4<f32>;
95 };
96
97 [[stage(fragment)]] fn main() -> FragmentOut {
98 var output : FragmentOut;
99 output.color0 = uBuffer.color0;
100 output.color1 = uBuffer.color1;
101 return output;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000102 })";
103
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000104 return CreateRenderPipelineForTest(kFsTwoOutputs, 2, false, sampleMask,
105 alphaToCoverageEnabled);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000106 }
107
Corentin Wallez6b087812020-10-27 15:35:56 +0000108 wgpu::Texture CreateTextureForRenderAttachment(wgpu::TextureFormat format,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000109 uint32_t sampleCount,
110 uint32_t mipLevelCount = 1,
111 uint32_t arrayLayerCount = 1) {
Corentin Wallezcab352c2019-10-28 13:27:36 +0000112 wgpu::TextureDescriptor descriptor;
113 descriptor.dimension = wgpu::TextureDimension::e2D;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000114 descriptor.size.width = kWidth << (mipLevelCount - 1);
115 descriptor.size.height = kHeight << (mipLevelCount - 1);
shrekshaob00de7f2021-03-22 21:12:36 +0000116 descriptor.size.depthOrArrayLayers = arrayLayerCount;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000117 descriptor.sampleCount = sampleCount;
118 descriptor.format = format;
119 descriptor.mipLevelCount = mipLevelCount;
Corentin Wallez6b087812020-10-27 15:35:56 +0000120 descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000121 return device.CreateTexture(&descriptor);
122 }
123
Corentin Wallezcab352c2019-10-28 13:27:36 +0000124 void EncodeRenderPassForTest(wgpu::CommandEncoder commandEncoder,
125 const wgpu::RenderPassDescriptor& renderPass,
126 const wgpu::RenderPipeline& pipeline,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000127 const float* uniformData,
128 uint32_t uniformDataSize) {
Corentin Wallezcab352c2019-10-28 13:27:36 +0000129 wgpu::Buffer uniformBuffer = utils::CreateBufferFromData(
130 device, uniformData, uniformDataSize, wgpu::BufferUsage::Uniform);
Austin Eng476a14a2019-12-03 21:18:05 +0000131 wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
Corentin Wallezcab352c2019-10-28 13:27:36 +0000132 {{0, uniformBuffer, 0, uniformDataSize}});
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000133
Corentin Wallezcab352c2019-10-28 13:27:36 +0000134 wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000135 renderPassEncoder.SetPipeline(pipeline);
Corentin Wallez70c8c102019-10-09 16:08:42 +0000136 renderPassEncoder.SetBindGroup(0, bindGroup);
Corentin Wallez67b1ad72020-03-31 16:21:35 +0000137 renderPassEncoder.Draw(3);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000138 renderPassEncoder.EndPass();
139 }
140
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000141 void EncodeRenderPassForTest(wgpu::CommandEncoder commandEncoder,
142 const wgpu::RenderPassDescriptor& renderPass,
143 const wgpu::RenderPipeline& pipeline,
144 const wgpu::Color& color) {
Brandon Jones670858d2020-09-22 16:51:36 +0000145 const float uniformData[4] = {static_cast<float>(color.r), static_cast<float>(color.g),
146 static_cast<float>(color.b), static_cast<float>(color.a)};
147 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, uniformData,
148 sizeof(float) * 4);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000149 }
150
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000151 utils::ComboRenderPassDescriptor CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000152 std::initializer_list<wgpu::TextureView> colorViews,
153 std::initializer_list<wgpu::TextureView> resolveTargetViews,
154 wgpu::LoadOp colorLoadOp,
155 wgpu::LoadOp depthStencilLoadOp,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000156 bool hasDepthStencilAttachment) {
157 ASSERT(colorViews.size() == resolveTargetViews.size());
158
Corentin Wallezcab352c2019-10-28 13:27:36 +0000159 constexpr wgpu::Color kClearColor = {0.0f, 0.0f, 0.0f, 0.0f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000160 constexpr float kClearDepth = 1.0f;
161
162 utils::ComboRenderPassDescriptor renderPass(colorViews);
163 uint32_t i = 0;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000164 for (const wgpu::TextureView& resolveTargetView : resolveTargetViews) {
Corentin Walleza838c7d2019-09-20 22:59:47 +0000165 renderPass.cColorAttachments[i].loadOp = colorLoadOp;
166 renderPass.cColorAttachments[i].clearColor = kClearColor;
167 renderPass.cColorAttachments[i].resolveTarget = resolveTargetView;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000168 ++i;
169 }
170
171 renderPass.cDepthStencilAttachmentInfo.clearDepth = kClearDepth;
172 renderPass.cDepthStencilAttachmentInfo.depthLoadOp = depthStencilLoadOp;
173
174 if (hasDepthStencilAttachment) {
Brandon Jones5e6a0922021-04-17 01:51:53 +0000175 renderPass.cDepthStencilAttachmentInfo.view = mDepthStencilView;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000176 renderPass.depthStencilAttachment = &renderPass.cDepthStencilAttachmentInfo;
177 }
178
179 return renderPass;
180 }
181
Corentin Wallezcab352c2019-10-28 13:27:36 +0000182 void VerifyResolveTarget(const wgpu::Color& inputColor,
183 wgpu::Texture resolveTexture,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000184 uint32_t mipmapLevel = 0,
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000185 uint32_t arrayLayer = 0,
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000186 const float msaaCoverage = 0.5f) {
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000187 // In this test we only check the pixel in the middle of the texture.
188 constexpr uint32_t kMiddleX = (kWidth - 1) / 2;
189 constexpr uint32_t kMiddleY = (kHeight - 1) / 2;
190
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000191 RGBA8 expectedColor = ExpectedMSAAColor(inputColor, msaaCoverage);
Yunchao He0da94c32021-04-08 14:58:42 +0000192 EXPECT_TEXTURE_EQ(&expectedColor, resolveTexture, {kMiddleX, kMiddleY, arrayLayer}, {1, 1},
193 mipmapLevel);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000194 }
195
196 constexpr static uint32_t kWidth = 3;
197 constexpr static uint32_t kHeight = 3;
198 constexpr static uint32_t kSampleCount = 4;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000199 constexpr static wgpu::TextureFormat kColorFormat = wgpu::TextureFormat::RGBA8Unorm;
200 constexpr static wgpu::TextureFormat kDepthStencilFormat =
201 wgpu::TextureFormat::Depth24PlusStencil8;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000202
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000203 constexpr static uint32_t kFirstSampleMaskBit = 0x00000001;
204 constexpr static uint32_t kSecondSampleMaskBit = 0x00000002;
205 constexpr static uint32_t kThirdSampleMaskBit = 0x00000004;
206 constexpr static uint32_t kFourthSampleMaskBit = 0x00000008;
207
Austin Eng8f9523e2020-06-19 16:21:33 +0000208 wgpu::Texture mMultisampledColorTexture;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000209 wgpu::TextureView mMultisampledColorView;
210 wgpu::Texture mResolveTexture;
211 wgpu::TextureView mResolveView;
212 wgpu::Texture mDepthStencilTexture;
213 wgpu::TextureView mDepthStencilView;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000214
Corentin Wallezcab352c2019-10-28 13:27:36 +0000215 wgpu::RenderPipeline CreateRenderPipelineForTest(const char* fs,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000216 uint32_t numColorAttachments,
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000217 bool hasDepthStencilAttachment,
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000218 uint32_t sampleMask = 0xFFFFFFFF,
219 bool alphaToCoverageEnabled = false,
220 bool flipTriangle = false) {
Brandon Jones41c87d92021-05-21 05:01:38 +0000221 utils::ComboRenderPipelineDescriptor pipelineDescriptor;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000222
223 // Draw a bottom-right triangle. In standard 4xMSAA pattern, for the pixels on diagonal,
224 // only two of the samples will be touched.
Corentin Wallez57090602021-03-19 09:48:11 +0000225 const char* vs = R"(
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000226 [[stage(vertex)]]
227 fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
Ben Clayton36edf8d2021-06-17 11:25:09 +0000228 var pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
Corentin Wallez57090602021-03-19 09:48:11 +0000229 vec2<f32>(-1.0, 1.0),
230 vec2<f32>( 1.0, 1.0),
231 vec2<f32>( 1.0, -1.0)
232 );
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000233 return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000234 })";
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000235
236 // Draw a bottom-left triangle.
Corentin Wallez57090602021-03-19 09:48:11 +0000237 const char* vsFlipped = R"(
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000238 [[stage(vertex)]]
239 fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
Ben Clayton36edf8d2021-06-17 11:25:09 +0000240 var pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
Corentin Wallez57090602021-03-19 09:48:11 +0000241 vec2<f32>(-1.0, 1.0),
242 vec2<f32>( 1.0, 1.0),
243 vec2<f32>(-1.0, -1.0)
244 );
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000245 return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000246 })";
247
248 if (flipTriangle) {
Corentin Wallez7aec4ae2021-03-24 15:55:32 +0000249 pipelineDescriptor.vertex.module = utils::CreateShaderModule(device, vsFlipped);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000250 } else {
Corentin Wallez7aec4ae2021-03-24 15:55:32 +0000251 pipelineDescriptor.vertex.module = utils::CreateShaderModule(device, vs);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000252 }
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000253
Corentin Wallez7aec4ae2021-03-24 15:55:32 +0000254 pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, fs);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000255
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000256 if (hasDepthStencilAttachment) {
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000257 wgpu::DepthStencilState* depthStencil =
258 pipelineDescriptor.EnableDepthStencil(kDepthStencilFormat);
259 depthStencil->depthWriteEnabled = true;
260 depthStencil->depthCompare = wgpu::CompareFunction::Less;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000261 }
262
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000263 pipelineDescriptor.multisample.count = kSampleCount;
264 pipelineDescriptor.multisample.mask = sampleMask;
265 pipelineDescriptor.multisample.alphaToCoverageEnabled = alphaToCoverageEnabled;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000266
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000267 pipelineDescriptor.cFragment.targetCount = numColorAttachments;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000268 for (uint32_t i = 0; i < numColorAttachments; ++i) {
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000269 pipelineDescriptor.cTargets[i].format = kColorFormat;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000270 }
271
Brandon Jones41c87d92021-05-21 05:01:38 +0000272 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
Austin Eng476a14a2019-12-03 21:18:05 +0000273 return pipeline;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000274 }
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000275
Brandon Jones670858d2020-09-22 16:51:36 +0000276 RGBA8 ExpectedMSAAColor(const wgpu::Color color, const double msaaCoverage) {
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000277 RGBA8 result;
Brandon Jones670858d2020-09-22 16:51:36 +0000278 result.r = static_cast<uint8_t>(std::min(255.0, 256 * color.r * msaaCoverage));
279 result.g = static_cast<uint8_t>(std::min(255.0, 256 * color.g * msaaCoverage));
280 result.b = static_cast<uint8_t>(std::min(255.0, 256 * color.b * msaaCoverage));
281 result.a = static_cast<uint8_t>(std::min(255.0, 256 * color.a * msaaCoverage));
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000282 return result;
283 }
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000284};
285
286// Test using one multisampled color attachment with resolve target can render correctly.
287TEST_P(MultisampledRenderingTest, ResolveInto2DTexture) {
288 constexpr bool kTestDepth = false;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000289 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000290
Corentin Wallezcab352c2019-10-28 13:27:36 +0000291 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000292
Kai Ninomiya57fcd172021-01-28 07:03:45 +0000293 // storeOp should not affect the result in the resolve target.
294 for (wgpu::StoreOp storeOp : {wgpu::StoreOp::Store, wgpu::StoreOp::Clear}) {
295 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
296
297 // Draw a green triangle.
298 {
299 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
300 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
301 kTestDepth);
302 renderPass.cColorAttachments[0].storeOp = storeOp;
303 std::array<float, 4> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a};
304 constexpr uint32_t kSize = sizeof(kUniformData);
305 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(),
306 kSize);
307 }
308
309 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
310 queue.Submit(1, &commandBuffer);
311
312 VerifyResolveTarget(kGreen, mResolveTexture);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000313 }
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000314}
315
Austin Eng8f9523e2020-06-19 16:21:33 +0000316// Test that a single-layer multisampled texture view can be created and resolved from.
317TEST_P(MultisampledRenderingTest, ResolveFromSingleLayerArrayInto2DTexture) {
318 constexpr bool kTestDepth = false;
319 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
320 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
321
322 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Austin Eng8f9523e2020-06-19 16:21:33 +0000323
324 // Draw a green triangle.
325 {
326 wgpu::TextureViewDescriptor desc = {};
327 desc.dimension = wgpu::TextureViewDimension::e2DArray;
328 desc.arrayLayerCount = 1;
329
330 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
331 {mMultisampledColorTexture.CreateView(&desc)}, {mResolveView}, wgpu::LoadOp::Clear,
332 wgpu::LoadOp::Clear, kTestDepth);
333
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000334 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Austin Eng8f9523e2020-06-19 16:21:33 +0000335 }
336
337 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
338 queue.Submit(1, &commandBuffer);
339
340 VerifyResolveTarget(kGreen, mResolveTexture);
341}
342
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000343// Test multisampled rendering with depth test works correctly.
344TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTest) {
345 constexpr bool kTestDepth = true;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000346 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
347 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000348
Corentin Wallezcab352c2019-10-28 13:27:36 +0000349 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
350 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000351
352 // In first render pass we draw a green triangle with depth value == 0.2f.
353 {
Corentin Wallezcab352c2019-10-28 13:27:36 +0000354 utils::ComboRenderPassDescriptor renderPass =
355 CreateComboRenderPassDescriptorForTest({mMultisampledColorView}, {mResolveView},
356 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, true);
Kai Ninomiya2afea0c2020-07-10 20:33:08 +0000357 std::array<float, 5> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a, // Color
358 0.2f}; // depth
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000359 constexpr uint32_t kSize = sizeof(kUniformData);
360 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
361 }
362
363 // In second render pass we draw a red triangle with depth value == 0.5f.
364 // This red triangle should not be displayed because it is behind the green one that is drawn in
365 // the last render pass.
366 {
367 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000368 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000369 kTestDepth);
370
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000371 std::array<float, 5> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color
Kai Ninomiya2afea0c2020-07-10 20:33:08 +0000372 0.5f}; // depth
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000373 constexpr uint32_t kSize = sizeof(kUniformData);
374 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
375 }
376
Corentin Wallezcab352c2019-10-28 13:27:36 +0000377 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000378 queue.Submit(1, &commandBuffer);
379
380 // The color of the pixel in the middle of mResolveTexture should be green if MSAA resolve runs
381 // correctly with depth test.
382 VerifyResolveTarget(kGreen, mResolveTexture);
383}
384
385// Test rendering into a multisampled color attachment and doing MSAA resolve in another render pass
386// works correctly.
387TEST_P(MultisampledRenderingTest, ResolveInAnotherRenderPass) {
388 constexpr bool kTestDepth = false;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000389 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
390 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000391
Corentin Wallezcab352c2019-10-28 13:27:36 +0000392 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000393
394 // In first render pass we draw a green triangle and do not set the resolve target.
395 {
396 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000397 {mMultisampledColorView}, {nullptr}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000398 kTestDepth);
399
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000400 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000401 }
402
403 // In second render pass we ony do MSAA resolve with no draw call.
404 {
405 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000406 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000407 kTestDepth);
408
Corentin Wallezcab352c2019-10-28 13:27:36 +0000409 wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000410 renderPassEncoder.EndPass();
411 }
412
Corentin Wallezcab352c2019-10-28 13:27:36 +0000413 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000414 queue.Submit(1, &commandBuffer);
415
416 VerifyResolveTarget(kGreen, mResolveTexture);
417}
418
419// Test doing MSAA resolve into multiple resolve targets works correctly.
420TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargets) {
Austin Enged8a8c02021-06-04 22:23:56 +0000421 // TODO(dawn:462): Issue in the D3D12 validation layers.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000422 DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsNvidia() && IsBackendValidationEnabled());
Bryan Bernhart1f162292020-07-27 19:50:21 +0000423
Corentin Wallezcab352c2019-10-28 13:27:36 +0000424 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000425 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
426 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000427 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000428
Corentin Wallezcab352c2019-10-28 13:27:36 +0000429 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
430 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithTwoOutputsForTest();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000431
Corentin Wallezcab352c2019-10-28 13:27:36 +0000432 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
433 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000434 constexpr bool kTestDepth = false;
435
436 // Draw a red triangle to the first color attachment, and a blue triangle to the second color
437 // attachment, and do MSAA resolve on two render targets in one render pass.
438 {
439 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
440 {mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2},
Corentin Wallezcab352c2019-10-28 13:27:36 +0000441 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000442
Brandon Jones670858d2020-09-22 16:51:36 +0000443 std::array<float, 8> kUniformData = {
444 static_cast<float>(kRed.r), static_cast<float>(kRed.g),
445 static_cast<float>(kRed.b), static_cast<float>(kRed.a),
446 static_cast<float>(kGreen.r), static_cast<float>(kGreen.g),
447 static_cast<float>(kGreen.b), static_cast<float>(kGreen.a)};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000448 constexpr uint32_t kSize = sizeof(kUniformData);
Brandon Jones670858d2020-09-22 16:51:36 +0000449
450 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000451 }
452
Corentin Wallezcab352c2019-10-28 13:27:36 +0000453 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000454 queue.Submit(1, &commandBuffer);
455
456 VerifyResolveTarget(kRed, mResolveTexture);
457 VerifyResolveTarget(kGreen, resolveTexture2);
458}
459
Jiawei Shao865cad82019-04-09 08:04:59 +0000460// Test doing MSAA resolve on one multisampled texture twice works correctly.
461TEST_P(MultisampledRenderingTest, ResolveOneMultisampledTextureTwice) {
462 constexpr bool kTestDepth = false;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000463 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
464 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Jiawei Shao865cad82019-04-09 08:04:59 +0000465
Corentin Wallezcab352c2019-10-28 13:27:36 +0000466 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Jiawei Shao865cad82019-04-09 08:04:59 +0000467
Corentin Wallez6b087812020-10-27 15:35:56 +0000468 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Jiawei Shao865cad82019-04-09 08:04:59 +0000469
470 // In first render pass we draw a green triangle and specify mResolveView as the resolve target.
471 {
472 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000473 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
Jiawei Shao865cad82019-04-09 08:04:59 +0000474 kTestDepth);
475
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000476 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Jiawei Shao865cad82019-04-09 08:04:59 +0000477 }
478
479 // In second render pass we do MSAA resolve into resolveTexture2.
480 {
Corentin Wallezcab352c2019-10-28 13:27:36 +0000481 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
Jiawei Shao865cad82019-04-09 08:04:59 +0000482 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000483 {mMultisampledColorView}, {resolveView2}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
Jiawei Shao865cad82019-04-09 08:04:59 +0000484 kTestDepth);
485
Corentin Wallezcab352c2019-10-28 13:27:36 +0000486 wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass);
Jiawei Shao865cad82019-04-09 08:04:59 +0000487 renderPassEncoder.EndPass();
488 }
489
Corentin Wallezcab352c2019-10-28 13:27:36 +0000490 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao865cad82019-04-09 08:04:59 +0000491 queue.Submit(1, &commandBuffer);
492
493 VerifyResolveTarget(kGreen, mResolveTexture);
494 VerifyResolveTarget(kGreen, resolveTexture2);
495}
496
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000497// Test using a layer of a 2D texture as resolve target works correctly.
498TEST_P(MultisampledRenderingTest, ResolveIntoOneMipmapLevelOf2DTexture) {
Austin Enged8a8c02021-06-04 22:23:56 +0000499 // TODO(dawn:462): Issue in the D3D12 validation layers.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000500 DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
Bryan Bernhart1f162292020-07-27 19:50:21 +0000501
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000502 constexpr uint32_t kBaseMipLevel = 2;
503
Corentin Wallezcab352c2019-10-28 13:27:36 +0000504 wgpu::TextureViewDescriptor textureViewDescriptor;
505 textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000506 textureViewDescriptor.format = kColorFormat;
507 textureViewDescriptor.baseArrayLayer = 0;
508 textureViewDescriptor.arrayLayerCount = 1;
509 textureViewDescriptor.mipLevelCount = 1;
510 textureViewDescriptor.baseMipLevel = kBaseMipLevel;
511
Corentin Wallezcab352c2019-10-28 13:27:36 +0000512 wgpu::Texture resolveTexture =
Corentin Wallez6b087812020-10-27 15:35:56 +0000513 CreateTextureForRenderAttachment(kColorFormat, 1, kBaseMipLevel + 1, 1);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000514 wgpu::TextureView resolveView = resolveTexture.CreateView(&textureViewDescriptor);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000515
Corentin Wallezcab352c2019-10-28 13:27:36 +0000516 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
517 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000518 constexpr bool kTestDepth = false;
519
520 // Draw a green triangle and do MSAA resolve.
521 {
522 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
Corentin Wallezcab352c2019-10-28 13:27:36 +0000523 {mMultisampledColorView}, {resolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000524 kTestDepth);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000525 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000526 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000527 }
528
Corentin Wallezcab352c2019-10-28 13:27:36 +0000529 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000530 queue.Submit(1, &commandBuffer);
531
532 VerifyResolveTarget(kGreen, resolveTexture, kBaseMipLevel, 0);
533}
534
535// Test using a level or a layer of a 2D array texture as resolve target works correctly.
536TEST_P(MultisampledRenderingTest, ResolveInto2DArrayTexture) {
Austin Enged8a8c02021-06-04 22:23:56 +0000537 // TODO(dawn:462): Issue in the D3D12 validation layers.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000538 DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
Bryan Bernhart1f162292020-07-27 19:50:21 +0000539
Corentin Wallezcab352c2019-10-28 13:27:36 +0000540 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000541 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000542
Corentin Wallezcab352c2019-10-28 13:27:36 +0000543 wgpu::TextureViewDescriptor baseTextureViewDescriptor;
544 baseTextureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000545 baseTextureViewDescriptor.format = kColorFormat;
546 baseTextureViewDescriptor.arrayLayerCount = 1;
547 baseTextureViewDescriptor.mipLevelCount = 1;
548
549 // Create resolveTexture1 with only 1 mipmap level.
550 constexpr uint32_t kBaseArrayLayer1 = 2;
551 constexpr uint32_t kBaseMipLevel1 = 0;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000552 wgpu::Texture resolveTexture1 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000553 CreateTextureForRenderAttachment(kColorFormat, 1, kBaseMipLevel1 + 1, kBaseArrayLayer1 + 1);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000554 wgpu::TextureViewDescriptor resolveViewDescriptor1 = baseTextureViewDescriptor;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000555 resolveViewDescriptor1.baseArrayLayer = kBaseArrayLayer1;
556 resolveViewDescriptor1.baseMipLevel = kBaseMipLevel1;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000557 wgpu::TextureView resolveView1 = resolveTexture1.CreateView(&resolveViewDescriptor1);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000558
559 // Create resolveTexture2 with (kBaseMipLevel2 + 1) mipmap levels and resolve into its last
560 // mipmap level.
561 constexpr uint32_t kBaseArrayLayer2 = 5;
562 constexpr uint32_t kBaseMipLevel2 = 3;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000563 wgpu::Texture resolveTexture2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000564 CreateTextureForRenderAttachment(kColorFormat, 1, kBaseMipLevel2 + 1, kBaseArrayLayer2 + 1);
Corentin Wallezcab352c2019-10-28 13:27:36 +0000565 wgpu::TextureViewDescriptor resolveViewDescriptor2 = baseTextureViewDescriptor;
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000566 resolveViewDescriptor2.baseArrayLayer = kBaseArrayLayer2;
567 resolveViewDescriptor2.baseMipLevel = kBaseMipLevel2;
Corentin Wallezcab352c2019-10-28 13:27:36 +0000568 wgpu::TextureView resolveView2 = resolveTexture2.CreateView(&resolveViewDescriptor2);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000569
Corentin Wallezcab352c2019-10-28 13:27:36 +0000570 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
571 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithTwoOutputsForTest();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000572
Corentin Wallezcab352c2019-10-28 13:27:36 +0000573 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
574 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000575 constexpr bool kTestDepth = false;
576
577 // Draw a red triangle to the first color attachment, and a green triangle to the second color
578 // attachment, and do MSAA resolve on two render targets in one render pass.
579 {
580 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
581 {mMultisampledColorView, multisampledColorView2}, {resolveView1, resolveView2},
Corentin Wallezcab352c2019-10-28 13:27:36 +0000582 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000583
Kai Ninomiya2afea0c2020-07-10 20:33:08 +0000584 std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1
585 kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000586 constexpr uint32_t kSize = sizeof(kUniformData);
587 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
588 }
589
Corentin Wallezcab352c2019-10-28 13:27:36 +0000590 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
Jiawei Shao0bc168e2019-03-28 14:18:11 +0000591 queue.Submit(1, &commandBuffer);
592
593 VerifyResolveTarget(kRed, resolveTexture1, kBaseMipLevel1, kBaseArrayLayer1);
594 VerifyResolveTarget(kGreen, resolveTexture2, kBaseMipLevel2, kBaseArrayLayer2);
595}
596
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000597// Test using one multisampled color attachment with resolve target can render correctly
598// with a non-default sample mask.
599TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithSampleMask) {
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000600 constexpr bool kTestDepth = false;
601 // The second and third samples are included,
602 // only the second one is covered by the triangle.
603 constexpr uint32_t kSampleMask = kSecondSampleMaskBit | kThirdSampleMaskBit;
604 constexpr float kMSAACoverage = 0.25f;
605 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
606 wgpu::RenderPipeline pipeline =
607 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMask);
608
609 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000610
611 // Draw a green triangle.
612 {
613 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
614 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
615 kTestDepth);
616
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000617 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000618 }
619
620 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
621 queue.Submit(1, &commandBuffer);
622
623 VerifyResolveTarget(kGreen, mResolveTexture, 0, 0, kMSAACoverage);
624}
625
626// Test using one multisampled color attachment with resolve target can render correctly
627// with the final sample mask empty.
628TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithEmptyFinalSampleMask) {
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000629 constexpr bool kTestDepth = false;
630 // The third and fourth samples are included,
631 // none of which is covered by the triangle.
632 constexpr uint32_t kSampleMask = kThirdSampleMaskBit | kFourthSampleMaskBit;
633 constexpr float kMSAACoverage = 0.00f;
634 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
635 wgpu::RenderPipeline pipeline =
636 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMask);
637
638 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000639
640 // Draw a green triangle.
641 {
642 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
643 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
644 kTestDepth);
645
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000646 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000647 }
648
649 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
650 queue.Submit(1, &commandBuffer);
651
652 VerifyResolveTarget(kGreen, mResolveTexture, 0, 0, kMSAACoverage);
653}
654
655// Test doing MSAA resolve into multiple resolve targets works correctly with a non-default sample
656// mask.
657TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargetsWithSampleMask) {
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000658 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000659 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
660 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000661 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
662
663 // The first and fourth samples are included,
664 // only the first one is covered by the triangle.
665 constexpr uint32_t kSampleMask = kFirstSampleMaskBit | kFourthSampleMaskBit;
666 constexpr float kMSAACoverage = 0.25f;
667
668 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
669 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithTwoOutputsForTest(kSampleMask);
670
671 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
672 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
673 constexpr bool kTestDepth = false;
674
675 // Draw a red triangle to the first color attachment, and a blue triangle to the second color
676 // attachment, and do MSAA resolve on two render targets in one render pass.
677 {
678 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
679 {mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2},
680 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
681
Brandon Jones670858d2020-09-22 16:51:36 +0000682 std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1
683 kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000684 constexpr uint32_t kSize = sizeof(kUniformData);
Brandon Jones670858d2020-09-22 16:51:36 +0000685 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000686 }
687
688 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
689 queue.Submit(1, &commandBuffer);
690
691 VerifyResolveTarget(kRed, mResolveTexture, 0, 0, kMSAACoverage);
692 VerifyResolveTarget(kGreen, resolveTexture2, 0, 0, kMSAACoverage);
693}
694
695// Test multisampled rendering with depth test works correctly with a non-default sample mask.
696TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTestAndSampleMask) {
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000697 constexpr bool kTestDepth = true;
698 // The second sample is included in the first render pass and it's covered by the triangle.
699 constexpr uint32_t kSampleMaskGreen = kSecondSampleMaskBit;
700 // The first and second samples are included in the second render pass,
701 // both are covered by the triangle.
702 constexpr uint32_t kSampleMaskRed = kFirstSampleMaskBit | kSecondSampleMaskBit;
703 constexpr float kMSAACoverage = 0.50f;
704
705 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
706 wgpu::RenderPipeline pipelineGreen =
707 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMaskGreen);
708 wgpu::RenderPipeline pipelineRed =
709 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMaskRed);
710
711 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
712 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
713
714 // In first render pass we draw a green triangle with depth value == 0.2f.
715 // We will only write to the second sample.
716 {
717 utils::ComboRenderPassDescriptor renderPass =
718 CreateComboRenderPassDescriptorForTest({mMultisampledColorView}, {mResolveView},
719 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, true);
720 std::array<float, 5> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a, // Color
721 0.2f}; // depth
722 constexpr uint32_t kSize = sizeof(kUniformData);
723 EncodeRenderPassForTest(commandEncoder, renderPass, pipelineGreen, kUniformData.data(),
724 kSize);
725 }
726
727 // In second render pass we draw a red triangle with depth value == 0.5f.
728 // We will only write to the first sample, since the second one is red with a smaller depth
729 // value.
730 {
731 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
732 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
733 kTestDepth);
734
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000735 std::array<float, 5> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000736 0.5f}; // depth
737 constexpr uint32_t kSize = sizeof(kUniformData);
738 EncodeRenderPassForTest(commandEncoder, renderPass, pipelineRed, kUniformData.data(),
739 kSize);
740 }
741
742 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
743 queue.Submit(1, &commandBuffer);
744
745 constexpr wgpu::Color kHalfGreenHalfRed = {(kGreen.r + kRed.r) / 2.0, (kGreen.g + kRed.g) / 2.0,
746 (kGreen.b + kRed.b) / 2.0,
747 (kGreen.a + kRed.a) / 2.0};
748
749 // The color of the pixel in the middle of mResolveTexture should be half green and half
750 // red if MSAA resolve runs correctly with depth test.
751 VerifyResolveTarget(kHalfGreenHalfRed, mResolveTexture, 0, 0, kMSAACoverage);
752}
753
754// Test using one multisampled color attachment with resolve target can render correctly
755// with non-default sample mask and shader-output mask.
756TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithSampleMaskAndShaderOutputMask) {
Ben Claytonbbc23542021-02-24 12:50:00 +0000757 // TODO(github.com/KhronosGroup/SPIRV-Cross/issues/1626): SPIRV-Cross produces bad GLSL for
758 // unsigned SampleMask builtins
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000759 DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("use_tint_generator") && (IsOpenGL() || IsOpenGLES()));
Austin Eng30805552020-12-08 16:49:34 +0000760
Stephen White725e03b2021-02-10 15:14:05 +0000761 // TODO(crbug.com/dawn/673): Work around or enforce via validation that sample variables are not
Stephen White02fd17c2021-02-10 02:28:17 +0000762 // supported on some platforms.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000763 DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_sample_variables"));
Stephen White0315c432021-01-26 12:53:38 +0000764
Austin Enged8a8c02021-06-04 22:23:56 +0000765 // TODO(crbug.com/dawn/571): Fails on Metal / D3D12 because SPIRV-Cross produces bad shaders
Corentin Wallez57090602021-03-19 09:48:11 +0000766 // for the SPIR-V outputted by Tint. Reenable once we use Tint's MSL / HLSL generators.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000767 DAWN_SUPPRESS_TEST_IF(IsD3D12() || IsMetal());
Corentin Wallez57090602021-03-19 09:48:11 +0000768
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000769 constexpr bool kTestDepth = false;
770 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
771
772 // The second and third samples are included in the shader-output mask.
773 // The first and third samples are included in the sample mask.
774 // Since we're now looking at a fully covered pixel, the rasterization mask
775 // includes all the samples.
776 // Thus the final mask includes only the third sample.
777 constexpr float kMSAACoverage = 0.25f;
778 constexpr uint32_t kSampleMask = kFirstSampleMaskBit | kThirdSampleMaskBit;
Corentin Wallez57090602021-03-19 09:48:11 +0000779 const char* fs = R"(
780 [[block]] struct U {
781 color : vec4<f32>;
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000782 };
Corentin Wallez57090602021-03-19 09:48:11 +0000783 [[group(0), binding(0)]] var<uniform> uBuffer : U;
Corentin Wallez57090602021-03-19 09:48:11 +0000784
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000785 struct FragmentOut {
786 [[location(0)]] color : vec4<f32>;
James Priceeae70b72021-04-19 15:29:49 +0000787 [[builtin(sample_mask)]] sampleMask : u32;
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000788 };
789
790 [[stage(fragment)]] fn main() -> FragmentOut {
791 var output : FragmentOut;
792 output.color = uBuffer.color;
793 output.sampleMask = 6u;
794 return output;
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000795 })";
796
797 wgpu::RenderPipeline pipeline = CreateRenderPipelineForTest(fs, 1, false, kSampleMask);
798 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000799
800 // Draw a green triangle.
801 {
802 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
803 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
804 kTestDepth);
805
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000806 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000807 }
808
809 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
810 queue.Submit(1, &commandBuffer);
811
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000812 RGBA8 expectedColor = ExpectedMSAAColor(kGreen, kMSAACoverage);
Yunchao He0da94c32021-04-08 14:58:42 +0000813 EXPECT_TEXTURE_EQ(&expectedColor, mResolveTexture, {1, 0}, {1, 1});
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000814}
815
816// Test doing MSAA resolve into multiple resolve targets works correctly with a non-default
817// shader-output mask.
818TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargetsWithShaderOutputMask) {
Ben Claytonbbc23542021-02-24 12:50:00 +0000819 // TODO(github.com/KhronosGroup/SPIRV-Cross/issues/1626): SPIRV-Cross produces bad GLSL for
820 // unsigned SampleMask builtins
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000821 DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("use_tint_generator") && (IsOpenGL() || IsOpenGLES()));
Austin Eng30805552020-12-08 16:49:34 +0000822
Stephen White725e03b2021-02-10 15:14:05 +0000823 // TODO(crbug.com/dawn/673): Work around or enforce via validation that sample variables are not
Stephen White02fd17c2021-02-10 02:28:17 +0000824 // supported on some platforms.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000825 DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_sample_variables"));
Stephen White0315c432021-01-26 12:53:38 +0000826
Austin Enged8a8c02021-06-04 22:23:56 +0000827 // TODO(crbug.com/dawn/571): Fails on Metal / D3D12 because SPIRV-Cross produces bad shaders
Corentin Wallez57090602021-03-19 09:48:11 +0000828 // for the SPIR-V outputted by Tint. Reenable once we use Tint's MSL / HLSL generators.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000829 DAWN_SUPPRESS_TEST_IF(IsD3D12() || IsMetal());
Corentin Wallez57090602021-03-19 09:48:11 +0000830
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000831 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000832 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
833 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000834 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
835
836 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
837 // The second and third samples are included in the shader-output mask,
838 // only the first one is covered by the triangle.
839 constexpr float kMSAACoverage = 0.25f;
Corentin Wallez57090602021-03-19 09:48:11 +0000840 const char* fs = R"(
841 [[block]] struct U {
842 color0 : vec4<f32>;
843 color1 : vec4<f32>;
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000844 };
Corentin Wallez57090602021-03-19 09:48:11 +0000845 [[group(0), binding(0)]] var<uniform> uBuffer : U;
Corentin Wallez57090602021-03-19 09:48:11 +0000846
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000847 struct FragmentOut {
848 [[location(0)]] color0 : vec4<f32>;
849 [[location(1)]] color1 : vec4<f32>;
James Priceeae70b72021-04-19 15:29:49 +0000850 [[builtin(sample_mask)]] sampleMask : u32;
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000851 };
852
853 [[stage(fragment)]] fn main() -> FragmentOut {
854 var output : FragmentOut;
855 output.color0 = uBuffer.color0;
856 output.color1 = uBuffer.color1;
857 output.sampleMask = 6u;
858 return output;
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000859 })";
860
861 wgpu::RenderPipeline pipeline = CreateRenderPipelineForTest(fs, 2, false);
862 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f};
863 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.8f};
864 constexpr bool kTestDepth = false;
865
866 // Draw a red triangle to the first color attachment, and a blue triangle to the second color
867 // attachment, and do MSAA resolve on two render targets in one render pass.
868 {
869 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
870 {mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2},
871 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
872
Brandon Jones670858d2020-09-22 16:51:36 +0000873 std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1
874 kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000875 constexpr uint32_t kSize = sizeof(kUniformData);
Brandon Jones670858d2020-09-22 16:51:36 +0000876 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
Tomek Ponitka4d9cadd2020-07-23 11:30:56 +0000877 }
878
879 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
880 queue.Submit(1, &commandBuffer);
881
882 VerifyResolveTarget(kRed, mResolveTexture, 0, 0, kMSAACoverage);
883 VerifyResolveTarget(kGreen, resolveTexture2, 0, 0, kMSAACoverage);
884}
885
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000886// Test using one multisampled color attachment with resolve target can render correctly
887// with alphaToCoverageEnabled.
888TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithAlphaToCoverage) {
889 constexpr bool kTestDepth = false;
890 constexpr uint32_t kSampleMask = 0xFFFFFFFF;
891 constexpr bool kAlphaToCoverageEnabled = true;
892
893 // Setting alpha <= 0 must result in alpha-to-coverage mask being empty.
894 // Setting alpha = 0.5f should result in alpha-to-coverage mask including half the samples,
895 // but this is not guaranteed by the spec. The Metal spec seems to guarantee that this is
896 // indeed the case.
897 // Setting alpha >= 1 must result in alpha-to-coverage mask being full.
898 for (float alpha : {-1.0f, 0.0f, 0.5f, 1.0f, 2.0f}) {
899 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
900 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(
901 kTestDepth, kSampleMask, kAlphaToCoverageEnabled);
902
903 const wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, alpha};
904
905 // Draw a green triangle.
906 {
907 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
908 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
909 kTestDepth);
910
911 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
912 }
913
914 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
915 queue.Submit(1, &commandBuffer);
916
917 // For alpha = {0, 0.5, 1} we expect msaaCoverage to correspond to the value of alpha.
918 float msaaCoverage = alpha;
919 if (alpha < 0.0f) {
920 msaaCoverage = 0.0f;
921 }
922 if (alpha > 1.0f) {
923 msaaCoverage = 1.0f;
924 }
925
926 RGBA8 expectedColor = ExpectedMSAAColor(kGreen, msaaCoverage);
Yunchao He0da94c32021-04-08 14:58:42 +0000927 EXPECT_TEXTURE_EQ(&expectedColor, mResolveTexture, {1, 0}, {1, 1});
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000928 }
929}
930
931// Test doing MSAA resolve into multiple resolve targets works correctly with
932// alphaToCoverage. The alphaToCoverage mask is computed based on the alpha
Corentin Wallez49a1f722021-01-22 19:51:37 +0000933// component of the first color render attachment.
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000934TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargetsWithAlphaToCoverage) {
935 wgpu::TextureView multisampledColorView2 =
Corentin Wallez6b087812020-10-27 15:35:56 +0000936 CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView();
937 wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1);
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000938 wgpu::TextureView resolveView2 = resolveTexture2.CreateView();
939 constexpr uint32_t kSampleMask = 0xFFFFFFFF;
940 constexpr float kMSAACoverage = 0.50f;
941 constexpr bool kAlphaToCoverageEnabled = true;
942
943 // The alpha-to-coverage mask should not depend on the alpha component of the
Corentin Wallez49a1f722021-01-22 19:51:37 +0000944 // second color render attachment.
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000945 // We test alpha = 0.51f and 0.99f instead of 0.50f and 1.00f because there are some rounding
946 // differences on QuadroP400 devices in that case.
947 for (float alpha : {0.0f, 0.51f, 0.99f}) {
948 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
949 wgpu::RenderPipeline pipeline =
950 CreateRenderPipelineWithTwoOutputsForTest(kSampleMask, kAlphaToCoverageEnabled);
951
952 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.51f};
953 const wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, alpha};
954 constexpr bool kTestDepth = false;
955
956 // Draw a red triangle to the first color attachment, and a blue triangle to the second
957 // color attachment, and do MSAA resolve on two render targets in one render pass.
958 {
959 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
960 {mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2},
961 wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
962
Brandon Jones670858d2020-09-22 16:51:36 +0000963 std::array<float, 8> kUniformData = {
964 static_cast<float>(kRed.r), static_cast<float>(kRed.g),
965 static_cast<float>(kRed.b), static_cast<float>(kRed.a),
966 static_cast<float>(kGreen.r), static_cast<float>(kGreen.g),
967 static_cast<float>(kGreen.b), static_cast<float>(kGreen.a)};
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000968 constexpr uint32_t kSize = sizeof(kUniformData);
Brandon Jones670858d2020-09-22 16:51:36 +0000969 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(),
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000970 kSize);
971 }
972
973 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
974 queue.Submit(1, &commandBuffer);
975
976 // Alpha to coverage affects both the color outputs, but the mask is computed
977 // using only the first one.
978 RGBA8 expectedRed = ExpectedMSAAColor(kRed, kMSAACoverage);
979 RGBA8 expectedGreen = ExpectedMSAAColor(kGreen, kMSAACoverage);
Yunchao He0da94c32021-04-08 14:58:42 +0000980 EXPECT_TEXTURE_EQ(&expectedRed, mResolveTexture, {1, 0}, {1, 1});
981 EXPECT_TEXTURE_EQ(&expectedGreen, resolveTexture2, {1, 0}, {1, 1});
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000982 }
983}
984
985// Test multisampled rendering with depth test works correctly with alphaToCoverage.
986TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTestAndAlphaToCoverage) {
Corentin Wallez6298b632020-10-19 18:35:39 +0000987 // This test fails because Swiftshader is off-by-one with its ((a+b)/2 + (c+d)/2)/2 fast resolve
988 // algorithm.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000989 DAWN_SUPPRESS_TEST_IF(IsSwiftshader() || IsANGLE());
Corentin Wallez6298b632020-10-19 18:35:39 +0000990
Tomek Ponitkaab04da42020-07-29 11:44:41 +0000991 constexpr bool kTestDepth = true;
992 constexpr uint32_t kSampleMask = 0xFFFFFFFF;
993
994 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
995 wgpu::RenderPipeline pipelineGreen =
996 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMask, true);
997 wgpu::RenderPipeline pipelineRed =
998 CreateRenderPipelineWithOneOutputForTest(kTestDepth, kSampleMask, false);
999
1000 // We test alpha = 0.51f and 0.81f instead of 0.50f and 0.80f because there are some
1001 // rounding differences on QuadroP400 devices in that case.
1002 constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.51f};
1003 constexpr wgpu::Color kRed = {0.8f, 0.0f, 0.0f, 0.81f};
1004
1005 // In first render pass we draw a green triangle with depth value == 0.2f.
1006 // We will only write to half the samples since the alphaToCoverage mode
1007 // is enabled for that render pass.
1008 {
1009 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
1010 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
1011 kTestDepth);
1012 std::array<float, 5> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a, // Color
1013 0.2f}; // depth
1014 constexpr uint32_t kSize = sizeof(kUniformData);
1015 EncodeRenderPassForTest(commandEncoder, renderPass, pipelineGreen, kUniformData.data(),
1016 kSize);
1017 }
1018
1019 // In second render pass we draw a red triangle with depth value == 0.5f.
1020 // We will write to all the samples since the alphaToCoverageMode is diabled for
1021 // that render pass.
1022 {
1023 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
1024 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
1025 kTestDepth);
1026
1027 std::array<float, 5> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color
1028 0.5f}; // depth
1029 constexpr uint32_t kSize = sizeof(kUniformData);
1030 EncodeRenderPassForTest(commandEncoder, renderPass, pipelineRed, kUniformData.data(),
1031 kSize);
1032 }
1033
1034 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
1035 queue.Submit(1, &commandBuffer);
1036
1037 constexpr wgpu::Color kHalfGreenHalfRed = {(kGreen.r + kRed.r) / 2.0, (kGreen.g + kRed.g) / 2.0,
1038 (kGreen.b + kRed.b) / 2.0,
1039 (kGreen.a + kRed.a) / 2.0};
1040 RGBA8 expectedColor = ExpectedMSAAColor(kHalfGreenHalfRed, 1.0f);
1041
Yunchao He0da94c32021-04-08 14:58:42 +00001042 EXPECT_TEXTURE_EQ(&expectedColor, mResolveTexture, {1, 0}, {1, 1});
Tomek Ponitkaab04da42020-07-29 11:44:41 +00001043}
1044
1045// Test using one multisampled color attachment with resolve target can render correctly
1046// with alphaToCoverageEnabled and a sample mask.
1047TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithAlphaToCoverageAndSampleMask) {
Corentin Wallez6298b632020-10-19 18:35:39 +00001048 // This test fails because Swiftshader is off-by-one with its ((a+b)/2 + (c+d)/2)/2 fast resolve
1049 // algorithm.
Jiawei Shao44fc6e32021-05-26 01:04:32 +00001050 DAWN_SUPPRESS_TEST_IF(IsSwiftshader() || IsANGLE());
Corentin Wallez6298b632020-10-19 18:35:39 +00001051
Tomek Ponitkaab04da42020-07-29 11:44:41 +00001052 // TODO(dawn:491): This doesn't work on Metal, because we're using both the shader-output
1053 // mask (emulting the sampleMask from RenderPipeline) and alpha-to-coverage at the same
1054 // time. See the issue: https://github.com/gpuweb/gpuweb/issues/959.
Jiawei Shao44fc6e32021-05-26 01:04:32 +00001055 DAWN_SUPPRESS_TEST_IF(IsMetal());
Tomek Ponitkaab04da42020-07-29 11:44:41 +00001056
1057 constexpr bool kTestDepth = false;
1058 constexpr float kMSAACoverage = 0.50f;
1059 constexpr uint32_t kSampleMask = kFirstSampleMaskBit | kThirdSampleMaskBit;
1060 constexpr bool kAlphaToCoverageEnabled = true;
1061
1062 // For those values of alpha we expect the proportion of samples to be covered
1063 // to correspond to the value of alpha.
1064 // We're assuming in the case of alpha = 0.50f that the implementation
1065 // dependendent algorithm will choose exactly one of the first and third samples.
1066 for (float alpha : {0.0f, 0.50f, 1.00f}) {
1067 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
1068 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(
1069 kTestDepth, kSampleMask, kAlphaToCoverageEnabled);
1070
1071 const wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, alpha - 0.01f};
1072
1073 // Draw a green triangle.
1074 {
1075 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
1076 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
1077 kTestDepth);
1078
1079 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
1080 }
1081
1082 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
1083 queue.Submit(1, &commandBuffer);
1084
1085 RGBA8 expectedColor = ExpectedMSAAColor(kGreen, kMSAACoverage * alpha);
Yunchao He0da94c32021-04-08 14:58:42 +00001086 EXPECT_TEXTURE_EQ(&expectedColor, mResolveTexture, {1, 0}, {1, 1});
Tomek Ponitkaab04da42020-07-29 11:44:41 +00001087 }
1088}
1089
1090// Test using one multisampled color attachment with resolve target can render correctly
1091// with alphaToCoverageEnabled and a rasterization mask.
1092TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithAlphaToCoverageAndRasterizationMask) {
Corentin Wallez6298b632020-10-19 18:35:39 +00001093 // This test fails because Swiftshader is off-by-one with its ((a+b)/2 + (c+d)/2)/2 fast resolve
1094 // algorithm.
Jiawei Shao44fc6e32021-05-26 01:04:32 +00001095 DAWN_SUPPRESS_TEST_IF(IsSwiftshader() || IsANGLE());
Corentin Wallez6298b632020-10-19 18:35:39 +00001096
Tomek Ponitkaab04da42020-07-29 11:44:41 +00001097 constexpr bool kTestDepth = false;
1098 constexpr float kMSAACoverage = 0.50f;
1099 constexpr uint32_t kSampleMask = 0xFFFFFFFF;
1100 constexpr bool kAlphaToCoverageEnabled = true;
1101 constexpr bool kFlipTriangle = true;
1102
1103 // For those values of alpha we expect the proportion of samples to be covered
1104 // to correspond to the value of alpha.
1105 // We're assuming in the case of alpha = 0.50f that the implementation
1106 // dependendent algorithm will choose exactly one of the samples covered by the
1107 // triangle.
1108 for (float alpha : {0.0f, 0.50f, 1.00f}) {
1109 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
1110 wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(
1111 kTestDepth, kSampleMask, kAlphaToCoverageEnabled, kFlipTriangle);
1112
1113 const wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, alpha - 0.01f};
1114
1115 // Draw a green triangle.
1116 {
1117 utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest(
1118 {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear,
1119 kTestDepth);
1120
1121 EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen);
1122 }
1123
1124 wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
1125 queue.Submit(1, &commandBuffer);
1126
1127 VerifyResolveTarget(kGreen, mResolveTexture, 0, 0, kMSAACoverage * alpha);
1128 }
1129}
1130
Jiawei Shao15d4c2e2019-04-26 07:52:57 +00001131DAWN_INSTANTIATE_TEST(MultisampledRenderingTest,
Austin Eng6c1d6462020-02-25 16:23:17 +00001132 D3D12Backend(),
1133 D3D12Backend({}, {"use_d3d12_resource_heap_tier2"}),
1134 D3D12Backend({}, {"use_d3d12_render_pass"}),
1135 MetalBackend(),
1136 OpenGLBackend(),
Stephen Whitef31b78e2020-12-04 15:59:29 +00001137 OpenGLESBackend(),
Austin Eng6c1d6462020-02-25 16:23:17 +00001138 VulkanBackend(),
1139 MetalBackend({"emulate_store_and_msaa_resolve"}),
1140 MetalBackend({"always_resolve_into_zero_level_and_layer"}),
1141 MetalBackend({"always_resolve_into_zero_level_and_layer",
Corentin Wallez84a57752019-12-05 14:02:11 +00001142 "emulate_store_and_msaa_resolve"}));