Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 1 | // 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 Wallez | 04863c4 | 2019-10-25 11:36:47 +0000 | [diff] [blame] | 19 | #include "utils/WGPUHelpers.h" |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 20 | |
| 21 | class MultisampledRenderingTest : public DawnTest { |
| 22 | protected: |
Austin Eng | 40dc5d3 | 2020-05-15 22:06:35 +0000 | [diff] [blame] | 23 | void SetUp() override { |
| 24 | DawnTest::SetUp(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 25 | |
| 26 | InitTexturesForTest(); |
| 27 | } |
| 28 | |
| 29 | void InitTexturesForTest() { |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 30 | mMultisampledColorTexture = CreateTextureForRenderAttachment(kColorFormat, kSampleCount); |
Austin Eng | 8f9523e | 2020-06-19 16:21:33 +0000 | [diff] [blame] | 31 | mMultisampledColorView = mMultisampledColorTexture.CreateView(); |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 32 | mResolveTexture = CreateTextureForRenderAttachment(kColorFormat, 1); |
Kai Ninomiya | 4078ed8 | 2019-08-27 17:56:23 +0000 | [diff] [blame] | 33 | mResolveView = mResolveTexture.CreateView(); |
Austin Eng | 342c6ea | 2019-04-18 18:28:48 +0000 | [diff] [blame] | 34 | |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 35 | mDepthStencilTexture = CreateTextureForRenderAttachment(kDepthStencilFormat, kSampleCount); |
Kai Ninomiya | 4078ed8 | 2019-08-27 17:56:23 +0000 | [diff] [blame] | 36 | mDepthStencilView = mDepthStencilTexture.CreateView(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 37 | } |
| 38 | |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 39 | wgpu::RenderPipeline CreateRenderPipelineWithOneOutputForTest( |
| 40 | bool testDepth, |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 41 | uint32_t sampleMask = 0xFFFFFFFF, |
| 42 | bool alphaToCoverageEnabled = false, |
| 43 | bool flipTriangle = false) { |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 44 | const char* kFsOneOutputWithDepth = R"( |
| 45 | [[block]] struct U { |
| 46 | color : vec4<f32>; |
| 47 | depth : f32; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 48 | }; |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 49 | [[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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 56 | })"; |
| 57 | |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 58 | const char* kFsOneOutputWithoutDepth = R"( |
| 59 | [[block]] struct U { |
| 60 | color : vec4<f32>; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 61 | }; |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 62 | [[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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 67 | })"; |
| 68 | |
| 69 | const char* fs = testDepth ? kFsOneOutputWithDepth : kFsOneOutputWithoutDepth; |
| 70 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 71 | return CreateRenderPipelineForTest(fs, 1, testDepth, sampleMask, alphaToCoverageEnabled, |
| 72 | flipTriangle); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 73 | } |
| 74 | |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 75 | wgpu::RenderPipeline CreateRenderPipelineWithTwoOutputsForTest( |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 76 | uint32_t sampleMask = 0xFFFFFFFF, |
| 77 | bool alphaToCoverageEnabled = false) { |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 78 | const char* kFsTwoOutputs = R"( |
| 79 | [[block]] struct U { |
| 80 | color0 : vec4<f32>; |
| 81 | color1 : vec4<f32>; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 82 | }; |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 83 | [[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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 90 | })"; |
| 91 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 92 | return CreateRenderPipelineForTest(kFsTwoOutputs, 2, false, sampleMask, |
| 93 | alphaToCoverageEnabled); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 94 | } |
| 95 | |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 96 | wgpu::Texture CreateTextureForRenderAttachment(wgpu::TextureFormat format, |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 97 | uint32_t sampleCount, |
| 98 | uint32_t mipLevelCount = 1, |
| 99 | uint32_t arrayLayerCount = 1) { |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 100 | wgpu::TextureDescriptor descriptor; |
| 101 | descriptor.dimension = wgpu::TextureDimension::e2D; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 102 | descriptor.size.width = kWidth << (mipLevelCount - 1); |
| 103 | descriptor.size.height = kHeight << (mipLevelCount - 1); |
shrekshao | b00de7f | 2021-03-22 21:12:36 +0000 | [diff] [blame^] | 104 | descriptor.size.depthOrArrayLayers = arrayLayerCount; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 105 | descriptor.sampleCount = sampleCount; |
| 106 | descriptor.format = format; |
| 107 | descriptor.mipLevelCount = mipLevelCount; |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 108 | descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 109 | return device.CreateTexture(&descriptor); |
| 110 | } |
| 111 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 112 | void EncodeRenderPassForTest(wgpu::CommandEncoder commandEncoder, |
| 113 | const wgpu::RenderPassDescriptor& renderPass, |
| 114 | const wgpu::RenderPipeline& pipeline, |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 115 | const float* uniformData, |
| 116 | uint32_t uniformDataSize) { |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 117 | wgpu::Buffer uniformBuffer = utils::CreateBufferFromData( |
| 118 | device, uniformData, uniformDataSize, wgpu::BufferUsage::Uniform); |
Austin Eng | 476a14a | 2019-12-03 21:18:05 +0000 | [diff] [blame] | 119 | wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 120 | {{0, uniformBuffer, 0, uniformDataSize}}); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 121 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 122 | wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 123 | renderPassEncoder.SetPipeline(pipeline); |
Corentin Wallez | 70c8c10 | 2019-10-09 16:08:42 +0000 | [diff] [blame] | 124 | renderPassEncoder.SetBindGroup(0, bindGroup); |
Corentin Wallez | 67b1ad7 | 2020-03-31 16:21:35 +0000 | [diff] [blame] | 125 | renderPassEncoder.Draw(3); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 126 | renderPassEncoder.EndPass(); |
| 127 | } |
| 128 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 129 | void EncodeRenderPassForTest(wgpu::CommandEncoder commandEncoder, |
| 130 | const wgpu::RenderPassDescriptor& renderPass, |
| 131 | const wgpu::RenderPipeline& pipeline, |
| 132 | const wgpu::Color& color) { |
Brandon Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 133 | 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 Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 137 | } |
| 138 | |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 139 | utils::ComboRenderPassDescriptor CreateComboRenderPassDescriptorForTest( |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 140 | std::initializer_list<wgpu::TextureView> colorViews, |
| 141 | std::initializer_list<wgpu::TextureView> resolveTargetViews, |
| 142 | wgpu::LoadOp colorLoadOp, |
| 143 | wgpu::LoadOp depthStencilLoadOp, |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 144 | bool hasDepthStencilAttachment) { |
| 145 | ASSERT(colorViews.size() == resolveTargetViews.size()); |
| 146 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 147 | constexpr wgpu::Color kClearColor = {0.0f, 0.0f, 0.0f, 0.0f}; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 148 | constexpr float kClearDepth = 1.0f; |
| 149 | |
| 150 | utils::ComboRenderPassDescriptor renderPass(colorViews); |
| 151 | uint32_t i = 0; |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 152 | for (const wgpu::TextureView& resolveTargetView : resolveTargetViews) { |
Corentin Wallez | a838c7d | 2019-09-20 22:59:47 +0000 | [diff] [blame] | 153 | renderPass.cColorAttachments[i].loadOp = colorLoadOp; |
| 154 | renderPass.cColorAttachments[i].clearColor = kClearColor; |
| 155 | renderPass.cColorAttachments[i].resolveTarget = resolveTargetView; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 156 | ++i; |
| 157 | } |
| 158 | |
| 159 | renderPass.cDepthStencilAttachmentInfo.clearDepth = kClearDepth; |
| 160 | renderPass.cDepthStencilAttachmentInfo.depthLoadOp = depthStencilLoadOp; |
| 161 | |
| 162 | if (hasDepthStencilAttachment) { |
Austin Eng | 342c6ea | 2019-04-18 18:28:48 +0000 | [diff] [blame] | 163 | renderPass.cDepthStencilAttachmentInfo.attachment = mDepthStencilView; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 164 | renderPass.depthStencilAttachment = &renderPass.cDepthStencilAttachmentInfo; |
| 165 | } |
| 166 | |
| 167 | return renderPass; |
| 168 | } |
| 169 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 170 | void VerifyResolveTarget(const wgpu::Color& inputColor, |
| 171 | wgpu::Texture resolveTexture, |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 172 | uint32_t mipmapLevel = 0, |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 173 | uint32_t arrayLayer = 0, |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 174 | const float msaaCoverage = 0.5f) { |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 175 | // 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 Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 179 | RGBA8 expectedColor = ExpectedMSAAColor(inputColor, msaaCoverage); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 180 | 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 Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 187 | constexpr static wgpu::TextureFormat kColorFormat = wgpu::TextureFormat::RGBA8Unorm; |
| 188 | constexpr static wgpu::TextureFormat kDepthStencilFormat = |
| 189 | wgpu::TextureFormat::Depth24PlusStencil8; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 190 | |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 191 | 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 Eng | 8f9523e | 2020-06-19 16:21:33 +0000 | [diff] [blame] | 196 | wgpu::Texture mMultisampledColorTexture; |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 197 | wgpu::TextureView mMultisampledColorView; |
| 198 | wgpu::Texture mResolveTexture; |
| 199 | wgpu::TextureView mResolveView; |
| 200 | wgpu::Texture mDepthStencilTexture; |
| 201 | wgpu::TextureView mDepthStencilView; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 202 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 203 | wgpu::RenderPipeline CreateRenderPipelineForTest(const char* fs, |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 204 | uint32_t numColorAttachments, |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 205 | bool hasDepthStencilAttachment, |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 206 | uint32_t sampleMask = 0xFFFFFFFF, |
| 207 | bool alphaToCoverageEnabled = false, |
| 208 | bool flipTriangle = false) { |
Brandon Jones | bff9d3a | 2021-03-18 02:54:27 +0000 | [diff] [blame] | 209 | utils::ComboRenderPipelineDescriptor2 pipelineDescriptor; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 210 | |
| 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 Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 213 | 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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 224 | })"; |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 225 | |
| 226 | // Draw a bottom-left triangle. |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 227 | 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 Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 238 | })"; |
| 239 | |
| 240 | if (flipTriangle) { |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 241 | pipelineDescriptor.vertex.module = utils::CreateShaderModuleFromWGSL(device, vsFlipped); |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 242 | } else { |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 243 | pipelineDescriptor.vertex.module = utils::CreateShaderModuleFromWGSL(device, vs); |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 244 | } |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 245 | |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 246 | pipelineDescriptor.cFragment.module = utils::CreateShaderModuleFromWGSL(device, fs); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 247 | |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 248 | if (hasDepthStencilAttachment) { |
Brandon Jones | bff9d3a | 2021-03-18 02:54:27 +0000 | [diff] [blame] | 249 | wgpu::DepthStencilState* depthStencil = |
| 250 | pipelineDescriptor.EnableDepthStencil(kDepthStencilFormat); |
| 251 | depthStencil->depthWriteEnabled = true; |
| 252 | depthStencil->depthCompare = wgpu::CompareFunction::Less; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 253 | } |
| 254 | |
Brandon Jones | bff9d3a | 2021-03-18 02:54:27 +0000 | [diff] [blame] | 255 | pipelineDescriptor.multisample.count = kSampleCount; |
| 256 | pipelineDescriptor.multisample.mask = sampleMask; |
| 257 | pipelineDescriptor.multisample.alphaToCoverageEnabled = alphaToCoverageEnabled; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 258 | |
Brandon Jones | bff9d3a | 2021-03-18 02:54:27 +0000 | [diff] [blame] | 259 | pipelineDescriptor.cFragment.targetCount = numColorAttachments; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 260 | for (uint32_t i = 0; i < numColorAttachments; ++i) { |
Brandon Jones | bff9d3a | 2021-03-18 02:54:27 +0000 | [diff] [blame] | 261 | pipelineDescriptor.cTargets[i].format = kColorFormat; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 262 | } |
| 263 | |
Brandon Jones | bff9d3a | 2021-03-18 02:54:27 +0000 | [diff] [blame] | 264 | wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&pipelineDescriptor); |
Austin Eng | 476a14a | 2019-12-03 21:18:05 +0000 | [diff] [blame] | 265 | return pipeline; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 266 | } |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 267 | |
Brandon Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 268 | RGBA8 ExpectedMSAAColor(const wgpu::Color color, const double msaaCoverage) { |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 269 | RGBA8 result; |
Brandon Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 270 | 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 Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 274 | return result; |
| 275 | } |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 276 | }; |
| 277 | |
| 278 | // Test using one multisampled color attachment with resolve target can render correctly. |
| 279 | TEST_P(MultisampledRenderingTest, ResolveInto2DTexture) { |
| 280 | constexpr bool kTestDepth = false; |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 281 | wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 282 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 283 | constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f}; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 284 | |
Kai Ninomiya | 57fcd17 | 2021-01-28 07:03:45 +0000 | [diff] [blame] | 285 | // 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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 305 | } |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 306 | } |
| 307 | |
Austin Eng | 8f9523e | 2020-06-19 16:21:33 +0000 | [diff] [blame] | 308 | // Test that a single-layer multisampled texture view can be created and resolved from. |
| 309 | TEST_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 Eng | 8f9523e | 2020-06-19 16:21:33 +0000 | [diff] [blame] | 315 | |
| 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 Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 326 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen); |
Austin Eng | 8f9523e | 2020-06-19 16:21:33 +0000 | [diff] [blame] | 327 | } |
| 328 | |
| 329 | wgpu::CommandBuffer commandBuffer = commandEncoder.Finish(); |
| 330 | queue.Submit(1, &commandBuffer); |
| 331 | |
| 332 | VerifyResolveTarget(kGreen, mResolveTexture); |
| 333 | } |
| 334 | |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 335 | // Test multisampled rendering with depth test works correctly. |
| 336 | TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTest) { |
| 337 | constexpr bool kTestDepth = true; |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 338 | wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| 339 | wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 340 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 341 | 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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 343 | |
| 344 | // In first render pass we draw a green triangle with depth value == 0.2f. |
| 345 | { |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 346 | utils::ComboRenderPassDescriptor renderPass = |
| 347 | CreateComboRenderPassDescriptorForTest({mMultisampledColorView}, {mResolveView}, |
| 348 | wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, true); |
Kai Ninomiya | 2afea0c | 2020-07-10 20:33:08 +0000 | [diff] [blame] | 349 | std::array<float, 5> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a, // Color |
| 350 | 0.2f}; // depth |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 351 | 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 Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 360 | {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load, |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 361 | kTestDepth); |
| 362 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 363 | std::array<float, 5> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color |
Kai Ninomiya | 2afea0c | 2020-07-10 20:33:08 +0000 | [diff] [blame] | 364 | 0.5f}; // depth |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 365 | constexpr uint32_t kSize = sizeof(kUniformData); |
| 366 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); |
| 367 | } |
| 368 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 369 | wgpu::CommandBuffer commandBuffer = commandEncoder.Finish(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 370 | 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. |
| 379 | TEST_P(MultisampledRenderingTest, ResolveInAnotherRenderPass) { |
| 380 | constexpr bool kTestDepth = false; |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 381 | wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| 382 | wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 383 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 384 | constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f}; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 385 | |
| 386 | // In first render pass we draw a green triangle and do not set the resolve target. |
| 387 | { |
| 388 | utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest( |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 389 | {mMultisampledColorView}, {nullptr}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 390 | kTestDepth); |
| 391 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 392 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 393 | } |
| 394 | |
| 395 | // In second render pass we ony do MSAA resolve with no draw call. |
| 396 | { |
| 397 | utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest( |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 398 | {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load, |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 399 | kTestDepth); |
| 400 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 401 | wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 402 | renderPassEncoder.EndPass(); |
| 403 | } |
| 404 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 405 | wgpu::CommandBuffer commandBuffer = commandEncoder.Finish(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 406 | queue.Submit(1, &commandBuffer); |
| 407 | |
| 408 | VerifyResolveTarget(kGreen, mResolveTexture); |
| 409 | } |
| 410 | |
| 411 | // Test doing MSAA resolve into multiple resolve targets works correctly. |
| 412 | TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargets) { |
Bryan Bernhart | 1f16229 | 2020-07-27 19:50:21 +0000 | [diff] [blame] | 413 | // TODO(dawn:462): Investigate backend validation failure. |
| 414 | DAWN_SKIP_TEST_IF(IsD3D12() && IsNvidia() && IsBackendValidationEnabled()); |
| 415 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 416 | wgpu::TextureView multisampledColorView2 = |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 417 | CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView(); |
| 418 | wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1); |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 419 | wgpu::TextureView resolveView2 = resolveTexture2.CreateView(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 420 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 421 | wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| 422 | wgpu::RenderPipeline pipeline = CreateRenderPipelineWithTwoOutputsForTest(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 423 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 424 | 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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 426 | 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 Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 433 | wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 434 | |
Brandon Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 435 | 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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 440 | constexpr uint32_t kSize = sizeof(kUniformData); |
Brandon Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 441 | |
| 442 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 443 | } |
| 444 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 445 | wgpu::CommandBuffer commandBuffer = commandEncoder.Finish(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 446 | queue.Submit(1, &commandBuffer); |
| 447 | |
| 448 | VerifyResolveTarget(kRed, mResolveTexture); |
| 449 | VerifyResolveTarget(kGreen, resolveTexture2); |
| 450 | } |
| 451 | |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 452 | // Test doing MSAA resolve on one multisampled texture twice works correctly. |
| 453 | TEST_P(MultisampledRenderingTest, ResolveOneMultisampledTextureTwice) { |
| 454 | constexpr bool kTestDepth = false; |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 455 | wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| 456 | wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth); |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 457 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 458 | constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f}; |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 459 | |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 460 | wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1); |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 461 | |
| 462 | // In first render pass we draw a green triangle and specify mResolveView as the resolve target. |
| 463 | { |
| 464 | utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest( |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 465 | {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 466 | kTestDepth); |
| 467 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 468 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen); |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 469 | } |
| 470 | |
| 471 | // In second render pass we do MSAA resolve into resolveTexture2. |
| 472 | { |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 473 | wgpu::TextureView resolveView2 = resolveTexture2.CreateView(); |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 474 | utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest( |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 475 | {mMultisampledColorView}, {resolveView2}, wgpu::LoadOp::Load, wgpu::LoadOp::Load, |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 476 | kTestDepth); |
| 477 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 478 | wgpu::RenderPassEncoder renderPassEncoder = commandEncoder.BeginRenderPass(&renderPass); |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 479 | renderPassEncoder.EndPass(); |
| 480 | } |
| 481 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 482 | wgpu::CommandBuffer commandBuffer = commandEncoder.Finish(); |
Jiawei Shao | 865cad8 | 2019-04-09 08:04:59 +0000 | [diff] [blame] | 483 | queue.Submit(1, &commandBuffer); |
| 484 | |
| 485 | VerifyResolveTarget(kGreen, mResolveTexture); |
| 486 | VerifyResolveTarget(kGreen, resolveTexture2); |
| 487 | } |
| 488 | |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 489 | // Test using a layer of a 2D texture as resolve target works correctly. |
| 490 | TEST_P(MultisampledRenderingTest, ResolveIntoOneMipmapLevelOf2DTexture) { |
Bryan Bernhart | 1f16229 | 2020-07-27 19:50:21 +0000 | [diff] [blame] | 491 | // TODO(dawn:462): Investigate backend validation failure. |
Jiawei Shao | 2fe7335 | 2020-11-30 13:50:49 +0000 | [diff] [blame] | 492 | DAWN_SKIP_TEST_IF(IsD3D12() && IsBackendValidationEnabled()); |
Bryan Bernhart | 1f16229 | 2020-07-27 19:50:21 +0000 | [diff] [blame] | 493 | |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 494 | constexpr uint32_t kBaseMipLevel = 2; |
| 495 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 496 | wgpu::TextureViewDescriptor textureViewDescriptor; |
| 497 | textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 498 | textureViewDescriptor.format = kColorFormat; |
| 499 | textureViewDescriptor.baseArrayLayer = 0; |
| 500 | textureViewDescriptor.arrayLayerCount = 1; |
| 501 | textureViewDescriptor.mipLevelCount = 1; |
| 502 | textureViewDescriptor.baseMipLevel = kBaseMipLevel; |
| 503 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 504 | wgpu::Texture resolveTexture = |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 505 | CreateTextureForRenderAttachment(kColorFormat, 1, kBaseMipLevel + 1, 1); |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 506 | wgpu::TextureView resolveView = resolveTexture.CreateView(&textureViewDescriptor); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 507 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 508 | wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| 509 | constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f}; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 510 | constexpr bool kTestDepth = false; |
| 511 | |
| 512 | // Draw a green triangle and do MSAA resolve. |
| 513 | { |
| 514 | utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest( |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 515 | {mMultisampledColorView}, {resolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 516 | kTestDepth); |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 517 | wgpu::RenderPipeline pipeline = CreateRenderPipelineWithOneOutputForTest(kTestDepth); |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 518 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 519 | } |
| 520 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 521 | wgpu::CommandBuffer commandBuffer = commandEncoder.Finish(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 522 | 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. |
| 528 | TEST_P(MultisampledRenderingTest, ResolveInto2DArrayTexture) { |
Bryan Bernhart | 1f16229 | 2020-07-27 19:50:21 +0000 | [diff] [blame] | 529 | // TODO(dawn:462): Investigate backend validation failure. |
Jiawei Shao | 2fe7335 | 2020-11-30 13:50:49 +0000 | [diff] [blame] | 530 | DAWN_SKIP_TEST_IF(IsD3D12() && IsBackendValidationEnabled()); |
Bryan Bernhart | 1f16229 | 2020-07-27 19:50:21 +0000 | [diff] [blame] | 531 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 532 | wgpu::TextureView multisampledColorView2 = |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 533 | CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 534 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 535 | wgpu::TextureViewDescriptor baseTextureViewDescriptor; |
| 536 | baseTextureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 537 | 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 Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 544 | wgpu::Texture resolveTexture1 = |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 545 | CreateTextureForRenderAttachment(kColorFormat, 1, kBaseMipLevel1 + 1, kBaseArrayLayer1 + 1); |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 546 | wgpu::TextureViewDescriptor resolveViewDescriptor1 = baseTextureViewDescriptor; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 547 | resolveViewDescriptor1.baseArrayLayer = kBaseArrayLayer1; |
| 548 | resolveViewDescriptor1.baseMipLevel = kBaseMipLevel1; |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 549 | wgpu::TextureView resolveView1 = resolveTexture1.CreateView(&resolveViewDescriptor1); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 550 | |
| 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 Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 555 | wgpu::Texture resolveTexture2 = |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 556 | CreateTextureForRenderAttachment(kColorFormat, 1, kBaseMipLevel2 + 1, kBaseArrayLayer2 + 1); |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 557 | wgpu::TextureViewDescriptor resolveViewDescriptor2 = baseTextureViewDescriptor; |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 558 | resolveViewDescriptor2.baseArrayLayer = kBaseArrayLayer2; |
| 559 | resolveViewDescriptor2.baseMipLevel = kBaseMipLevel2; |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 560 | wgpu::TextureView resolveView2 = resolveTexture2.CreateView(&resolveViewDescriptor2); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 561 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 562 | wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); |
| 563 | wgpu::RenderPipeline pipeline = CreateRenderPipelineWithTwoOutputsForTest(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 564 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 565 | 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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 567 | 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 Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 574 | wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 575 | |
Kai Ninomiya | 2afea0c | 2020-07-10 20:33:08 +0000 | [diff] [blame] | 576 | 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 Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 578 | constexpr uint32_t kSize = sizeof(kUniformData); |
| 579 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); |
| 580 | } |
| 581 | |
Corentin Wallez | cab352c | 2019-10-28 13:27:36 +0000 | [diff] [blame] | 582 | wgpu::CommandBuffer commandBuffer = commandEncoder.Finish(); |
Jiawei Shao | 0bc168e | 2019-03-28 14:18:11 +0000 | [diff] [blame] | 583 | queue.Submit(1, &commandBuffer); |
| 584 | |
| 585 | VerifyResolveTarget(kRed, resolveTexture1, kBaseMipLevel1, kBaseArrayLayer1); |
| 586 | VerifyResolveTarget(kGreen, resolveTexture2, kBaseMipLevel2, kBaseArrayLayer2); |
| 587 | } |
| 588 | |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 589 | // Test using one multisampled color attachment with resolve target can render correctly |
| 590 | // with a non-default sample mask. |
| 591 | TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithSampleMask) { |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 592 | 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 Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 602 | |
| 603 | // Draw a green triangle. |
| 604 | { |
| 605 | utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest( |
| 606 | {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, |
| 607 | kTestDepth); |
| 608 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 609 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen); |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 610 | } |
| 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. |
| 620 | TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithEmptyFinalSampleMask) { |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 621 | 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 Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 631 | |
| 632 | // Draw a green triangle. |
| 633 | { |
| 634 | utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest( |
| 635 | {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, |
| 636 | kTestDepth); |
| 637 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 638 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen); |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 639 | } |
| 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. |
| 649 | TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargetsWithSampleMask) { |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 650 | wgpu::TextureView multisampledColorView2 = |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 651 | CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView(); |
| 652 | wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1); |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 653 | 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 Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 674 | 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 Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 676 | constexpr uint32_t kSize = sizeof(kUniformData); |
Brandon Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 677 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 678 | } |
| 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. |
| 688 | TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTestAndSampleMask) { |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 689 | 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 Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 727 | std::array<float, 5> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 728 | 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. |
| 748 | TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithSampleMaskAndShaderOutputMask) { |
Ben Clayton | bbc2354 | 2021-02-24 12:50:00 +0000 | [diff] [blame] | 749 | // 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 Eng | 3080555 | 2020-12-08 16:49:34 +0000 | [diff] [blame] | 752 | |
Stephen White | 725e03b | 2021-02-10 15:14:05 +0000 | [diff] [blame] | 753 | // TODO(crbug.com/dawn/673): Work around or enforce via validation that sample variables are not |
Stephen White | 02fd17c | 2021-02-10 02:28:17 +0000 | [diff] [blame] | 754 | // supported on some platforms. |
| 755 | DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_sample_variables")); |
Stephen White | 0315c43 | 2021-01-26 12:53:38 +0000 | [diff] [blame] | 756 | |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 757 | // 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 Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 761 | 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 Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 771 | const char* fs = R"( |
| 772 | [[block]] struct U { |
| 773 | color : vec4<f32>; |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 774 | }; |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 775 | [[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 Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 782 | })"; |
| 783 | |
| 784 | wgpu::RenderPipeline pipeline = CreateRenderPipelineForTest(fs, 1, false, kSampleMask); |
| 785 | constexpr wgpu::Color kGreen = {0.0f, 0.8f, 0.0f, 0.8f}; |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 786 | |
| 787 | // Draw a green triangle. |
| 788 | { |
| 789 | utils::ComboRenderPassDescriptor renderPass = CreateComboRenderPassDescriptorForTest( |
| 790 | {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, |
| 791 | kTestDepth); |
| 792 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 793 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kGreen); |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 794 | } |
| 795 | |
| 796 | wgpu::CommandBuffer commandBuffer = commandEncoder.Finish(); |
| 797 | queue.Submit(1, &commandBuffer); |
| 798 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 799 | RGBA8 expectedColor = ExpectedMSAAColor(kGreen, kMSAACoverage); |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 800 | 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. |
| 805 | TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargetsWithShaderOutputMask) { |
Ben Clayton | bbc2354 | 2021-02-24 12:50:00 +0000 | [diff] [blame] | 806 | // 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 Eng | 3080555 | 2020-12-08 16:49:34 +0000 | [diff] [blame] | 809 | |
Stephen White | 725e03b | 2021-02-10 15:14:05 +0000 | [diff] [blame] | 810 | // TODO(crbug.com/dawn/673): Work around or enforce via validation that sample variables are not |
Stephen White | 02fd17c | 2021-02-10 02:28:17 +0000 | [diff] [blame] | 811 | // supported on some platforms. |
| 812 | DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_sample_variables")); |
Stephen White | 0315c43 | 2021-01-26 12:53:38 +0000 | [diff] [blame] | 813 | |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 814 | // 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 Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 818 | wgpu::TextureView multisampledColorView2 = |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 819 | CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView(); |
| 820 | wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1); |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 821 | 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 Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 827 | const char* fs = R"( |
| 828 | [[block]] struct U { |
| 829 | color0 : vec4<f32>; |
| 830 | color1 : vec4<f32>; |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 831 | }; |
Corentin Wallez | 5709060 | 2021-03-19 09:48:11 +0000 | [diff] [blame] | 832 | [[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 Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 841 | })"; |
| 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 Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 855 | 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 Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 857 | constexpr uint32_t kSize = sizeof(kUniformData); |
Brandon Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 858 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); |
Tomek Ponitka | 4d9cadd | 2020-07-23 11:30:56 +0000 | [diff] [blame] | 859 | } |
| 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 Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 868 | // Test using one multisampled color attachment with resolve target can render correctly |
| 869 | // with alphaToCoverageEnabled. |
| 870 | TEST_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 Wallez | 49a1f72 | 2021-01-22 19:51:37 +0000 | [diff] [blame] | 915 | // component of the first color render attachment. |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 916 | TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargetsWithAlphaToCoverage) { |
| 917 | wgpu::TextureView multisampledColorView2 = |
Corentin Wallez | 6b08781 | 2020-10-27 15:35:56 +0000 | [diff] [blame] | 918 | CreateTextureForRenderAttachment(kColorFormat, kSampleCount).CreateView(); |
| 919 | wgpu::Texture resolveTexture2 = CreateTextureForRenderAttachment(kColorFormat, 1); |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 920 | 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 Wallez | 49a1f72 | 2021-01-22 19:51:37 +0000 | [diff] [blame] | 926 | // second color render attachment. |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 927 | // 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 Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 945 | 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 Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 950 | constexpr uint32_t kSize = sizeof(kUniformData); |
Brandon Jones | 670858d | 2020-09-22 16:51:36 +0000 | [diff] [blame] | 951 | EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 952 | 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. |
| 968 | TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTestAndAlphaToCoverage) { |
Corentin Wallez | 6298b63 | 2020-10-19 18:35:39 +0000 | [diff] [blame] | 969 | // This test fails because Swiftshader is off-by-one with its ((a+b)/2 + (c+d)/2)/2 fast resolve |
| 970 | // algorithm. |
Stephen White | 0315c43 | 2021-01-26 12:53:38 +0000 | [diff] [blame] | 971 | DAWN_SKIP_TEST_IF(IsSwiftshader() || IsANGLE()); |
Corentin Wallez | 6298b63 | 2020-10-19 18:35:39 +0000 | [diff] [blame] | 972 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 973 | 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. |
| 1029 | TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithAlphaToCoverageAndSampleMask) { |
Corentin Wallez | 6298b63 | 2020-10-19 18:35:39 +0000 | [diff] [blame] | 1030 | // This test fails because Swiftshader is off-by-one with its ((a+b)/2 + (c+d)/2)/2 fast resolve |
| 1031 | // algorithm. |
Stephen White | 0315c43 | 2021-01-26 12:53:38 +0000 | [diff] [blame] | 1032 | DAWN_SKIP_TEST_IF(IsSwiftshader() || IsANGLE()); |
Corentin Wallez | 6298b63 | 2020-10-19 18:35:39 +0000 | [diff] [blame] | 1033 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 1034 | // 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. |
| 1074 | TEST_P(MultisampledRenderingTest, ResolveInto2DTextureWithAlphaToCoverageAndRasterizationMask) { |
Corentin Wallez | 6298b63 | 2020-10-19 18:35:39 +0000 | [diff] [blame] | 1075 | // This test fails because Swiftshader is off-by-one with its ((a+b)/2 + (c+d)/2)/2 fast resolve |
| 1076 | // algorithm. |
Stephen White | 0315c43 | 2021-01-26 12:53:38 +0000 | [diff] [blame] | 1077 | DAWN_SKIP_TEST_IF(IsSwiftshader() || IsANGLE()); |
Corentin Wallez | 6298b63 | 2020-10-19 18:35:39 +0000 | [diff] [blame] | 1078 | |
Tomek Ponitka | ab04da4 | 2020-07-29 11:44:41 +0000 | [diff] [blame] | 1079 | 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 Shao | 15d4c2e | 2019-04-26 07:52:57 +0000 | [diff] [blame] | 1113 | DAWN_INSTANTIATE_TEST(MultisampledRenderingTest, |
Austin Eng | 6c1d646 | 2020-02-25 16:23:17 +0000 | [diff] [blame] | 1114 | D3D12Backend(), |
| 1115 | D3D12Backend({}, {"use_d3d12_resource_heap_tier2"}), |
| 1116 | D3D12Backend({}, {"use_d3d12_render_pass"}), |
| 1117 | MetalBackend(), |
| 1118 | OpenGLBackend(), |
Stephen White | f31b78e | 2020-12-04 15:59:29 +0000 | [diff] [blame] | 1119 | OpenGLESBackend(), |
Austin Eng | 6c1d646 | 2020-02-25 16:23:17 +0000 | [diff] [blame] | 1120 | 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 Wallez | 84a5775 | 2019-12-05 14:02:11 +0000 | [diff] [blame] | 1124 | "emulate_store_and_msaa_resolve"})); |