• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 <algorithm>
16 #include <array>
17 #include <cmath>
18 
19 #include "tests/DawnTest.h"
20 
21 #include "common/Assert.h"
22 #include "common/Constants.h"
23 #include "utils/ComboRenderPipelineDescriptor.h"
24 #include "utils/WGPUHelpers.h"
25 
26 constexpr static unsigned int kRTSize = 64;
27 
28 class ColorStateTest : public DawnTest {
29   protected:
SetUp()30     void SetUp() override {
31         DawnTest::SetUp();
32 
33         wgpu::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
34             device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Uniform}});
35         pipelineLayout = utils::MakePipelineLayout(device, {bindGroupLayout});
36 
37         // TODO(crbug.com/dawn/489): D3D12_Microsoft_Basic_Render_Driver_CPU
38         // produces invalid results for these tests.
39         DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP());
40 
41         vsModule = utils::CreateShaderModule(device, R"(
42                 [[stage(vertex)]]
43                 fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
44                     var pos = array<vec2<f32>, 3>(
45                         vec2<f32>(-1.0, -1.0),
46                         vec2<f32>(3.0, -1.0),
47                         vec2<f32>(-1.0, 3.0));
48                     return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
49                 }
50             )");
51 
52         renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
53     }
54 
55     struct TriangleSpec {
56         RGBA8 color;
57         std::array<float, 4> blendFactor = {};
58     };
59 
60     // Set up basePipeline and testPipeline. testPipeline has the given blend state on the first
61     // attachment. basePipeline has no blending
SetupSingleSourcePipelines(wgpu::ColorTargetState colorTargetState)62     void SetupSingleSourcePipelines(wgpu::ColorTargetState colorTargetState) {
63         wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
64                 [[block]] struct MyBlock {
65                     color : vec4<f32>;
66                 };
67 
68                 [[group(0), binding(0)]] var<uniform> myUbo : MyBlock;
69 
70                 [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
71                     return myUbo.color;
72                 }
73             )");
74 
75         utils::ComboRenderPipelineDescriptor baseDescriptor;
76         baseDescriptor.layout = pipelineLayout;
77         baseDescriptor.vertex.module = vsModule;
78         baseDescriptor.cFragment.module = fsModule;
79         baseDescriptor.cTargets[0].format = renderPass.colorFormat;
80 
81         basePipeline = device.CreateRenderPipeline(&baseDescriptor);
82 
83         utils::ComboRenderPipelineDescriptor testDescriptor;
84         testDescriptor.layout = pipelineLayout;
85         testDescriptor.vertex.module = vsModule;
86         testDescriptor.cFragment.module = fsModule;
87         testDescriptor.cTargets[0] = colorTargetState;
88         testDescriptor.cTargets[0].format = renderPass.colorFormat;
89 
90         testPipeline = device.CreateRenderPipeline(&testDescriptor);
91     }
92 
93     // Create a bind group to set the colors as a uniform buffer
94     template <size_t N>
MakeBindGroupForColors(std::array<RGBA8,N> colors)95     wgpu::BindGroup MakeBindGroupForColors(std::array<RGBA8, N> colors) {
96         std::array<float, 4 * N> data;
97         for (unsigned int i = 0; i < N; ++i) {
98             data[4 * i + 0] = static_cast<float>(colors[i].r) / 255.f;
99             data[4 * i + 1] = static_cast<float>(colors[i].g) / 255.f;
100             data[4 * i + 2] = static_cast<float>(colors[i].b) / 255.f;
101             data[4 * i + 3] = static_cast<float>(colors[i].a) / 255.f;
102         }
103 
104         uint32_t bufferSize = static_cast<uint32_t>(4 * N * sizeof(float));
105 
106         wgpu::Buffer buffer =
107             utils::CreateBufferFromData(device, &data, bufferSize, wgpu::BufferUsage::Uniform);
108         return utils::MakeBindGroup(device, testPipeline.GetBindGroupLayout(0),
109                                     {{0, buffer, 0, bufferSize}});
110     }
111 
112     // Test that after drawing a triangle with the base color, and then the given triangle spec, the
113     // color is as expected
DoSingleSourceTest(RGBA8 base,const TriangleSpec & triangle,const RGBA8 & expected)114     void DoSingleSourceTest(RGBA8 base, const TriangleSpec& triangle, const RGBA8& expected) {
115         wgpu::Color blendConstant{triangle.blendFactor[0], triangle.blendFactor[1],
116                                   triangle.blendFactor[2], triangle.blendFactor[3]};
117 
118         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
119         {
120             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
121             // First use the base pipeline to draw a triangle with no blending
122             pass.SetPipeline(basePipeline);
123             pass.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({{base}})));
124             pass.Draw(3);
125 
126             // Then use the test pipeline to draw the test triangle with blending
127             pass.SetPipeline(testPipeline);
128             pass.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({{triangle.color}})));
129             pass.SetBlendConstant(&blendConstant);
130             pass.Draw(3);
131             pass.EndPass();
132         }
133 
134         wgpu::CommandBuffer commands = encoder.Finish();
135         queue.Submit(1, &commands);
136 
137         EXPECT_PIXEL_RGBA8_EQ(expected, renderPass.color, kRTSize / 2, kRTSize / 2);
138     }
139 
140     // Given a vector of tests where each element is <testColor, expectedColor>, check that all
141     // expectations are true for the given blend operation
CheckBlendOperation(RGBA8 base,wgpu::BlendOperation operation,std::vector<std::pair<RGBA8,RGBA8>> tests)142     void CheckBlendOperation(RGBA8 base,
143                              wgpu::BlendOperation operation,
144                              std::vector<std::pair<RGBA8, RGBA8>> tests) {
145         wgpu::BlendComponent blendComponent;
146         blendComponent.operation = operation;
147         blendComponent.srcFactor = wgpu::BlendFactor::One;
148         blendComponent.dstFactor = wgpu::BlendFactor::One;
149 
150         wgpu::BlendState blend;
151         blend.color = blendComponent;
152         blend.alpha = blendComponent;
153 
154         wgpu::ColorTargetState descriptor;
155         descriptor.blend = &blend;
156         descriptor.writeMask = wgpu::ColorWriteMask::All;
157 
158         SetupSingleSourcePipelines(descriptor);
159 
160         for (const auto& test : tests) {
161             DoSingleSourceTest(base, {test.first}, test.second);
162         }
163     }
164 
165     // Given a vector of tests where each element is <testSpec, expectedColor>, check that all
166     // expectations are true for the given blend factors
CheckBlendFactor(RGBA8 base,wgpu::BlendFactor colorSrcFactor,wgpu::BlendFactor colorDstFactor,wgpu::BlendFactor alphaSrcFactor,wgpu::BlendFactor alphaDstFactor,std::vector<std::pair<TriangleSpec,RGBA8>> tests)167     void CheckBlendFactor(RGBA8 base,
168                           wgpu::BlendFactor colorSrcFactor,
169                           wgpu::BlendFactor colorDstFactor,
170                           wgpu::BlendFactor alphaSrcFactor,
171                           wgpu::BlendFactor alphaDstFactor,
172                           std::vector<std::pair<TriangleSpec, RGBA8>> tests) {
173         wgpu::BlendComponent colorBlend;
174         colorBlend.operation = wgpu::BlendOperation::Add;
175         colorBlend.srcFactor = colorSrcFactor;
176         colorBlend.dstFactor = colorDstFactor;
177 
178         wgpu::BlendComponent alphaBlend;
179         alphaBlend.operation = wgpu::BlendOperation::Add;
180         alphaBlend.srcFactor = alphaSrcFactor;
181         alphaBlend.dstFactor = alphaDstFactor;
182 
183         wgpu::BlendState blend;
184         blend.color = colorBlend;
185         blend.alpha = alphaBlend;
186 
187         wgpu::ColorTargetState descriptor;
188         descriptor.blend = &blend;
189         descriptor.writeMask = wgpu::ColorWriteMask::All;
190 
191         SetupSingleSourcePipelines(descriptor);
192 
193         for (const auto& test : tests) {
194             DoSingleSourceTest(base, test.first, test.second);
195         }
196     }
197 
CheckSrcBlendFactor(RGBA8 base,wgpu::BlendFactor colorFactor,wgpu::BlendFactor alphaFactor,std::vector<std::pair<TriangleSpec,RGBA8>> tests)198     void CheckSrcBlendFactor(RGBA8 base,
199                              wgpu::BlendFactor colorFactor,
200                              wgpu::BlendFactor alphaFactor,
201                              std::vector<std::pair<TriangleSpec, RGBA8>> tests) {
202         CheckBlendFactor(base, colorFactor, wgpu::BlendFactor::One, alphaFactor,
203                          wgpu::BlendFactor::One, tests);
204     }
205 
CheckDstBlendFactor(RGBA8 base,wgpu::BlendFactor colorFactor,wgpu::BlendFactor alphaFactor,std::vector<std::pair<TriangleSpec,RGBA8>> tests)206     void CheckDstBlendFactor(RGBA8 base,
207                              wgpu::BlendFactor colorFactor,
208                              wgpu::BlendFactor alphaFactor,
209                              std::vector<std::pair<TriangleSpec, RGBA8>> tests) {
210         CheckBlendFactor(base, wgpu::BlendFactor::One, colorFactor, wgpu::BlendFactor::One,
211                          alphaFactor, tests);
212     }
213 
214     wgpu::PipelineLayout pipelineLayout;
215     utils::BasicRenderPass renderPass;
216     wgpu::RenderPipeline basePipeline;
217     wgpu::RenderPipeline testPipeline;
218     wgpu::ShaderModule vsModule;
219 };
220 
221 namespace {
222     // Add two colors and clamp
operator +(const RGBA8 & col1,const RGBA8 & col2)223     constexpr RGBA8 operator+(const RGBA8& col1, const RGBA8& col2) {
224         int r = static_cast<int>(col1.r) + static_cast<int>(col2.r);
225         int g = static_cast<int>(col1.g) + static_cast<int>(col2.g);
226         int b = static_cast<int>(col1.b) + static_cast<int>(col2.b);
227         int a = static_cast<int>(col1.a) + static_cast<int>(col2.a);
228         r = (r > 255 ? 255 : (r < 0 ? 0 : r));
229         g = (g > 255 ? 255 : (g < 0 ? 0 : g));
230         b = (b > 255 ? 255 : (b < 0 ? 0 : b));
231         a = (a > 255 ? 255 : (a < 0 ? 0 : a));
232 
233         return RGBA8(static_cast<uint8_t>(r), static_cast<uint8_t>(g), static_cast<uint8_t>(b),
234                      static_cast<uint8_t>(a));
235     }
236 
237     // Subtract two colors and clamp
operator -(const RGBA8 & col1,const RGBA8 & col2)238     constexpr RGBA8 operator-(const RGBA8& col1, const RGBA8& col2) {
239         int r = static_cast<int>(col1.r) - static_cast<int>(col2.r);
240         int g = static_cast<int>(col1.g) - static_cast<int>(col2.g);
241         int b = static_cast<int>(col1.b) - static_cast<int>(col2.b);
242         int a = static_cast<int>(col1.a) - static_cast<int>(col2.a);
243         r = (r > 255 ? 255 : (r < 0 ? 0 : r));
244         g = (g > 255 ? 255 : (g < 0 ? 0 : g));
245         b = (b > 255 ? 255 : (b < 0 ? 0 : b));
246         a = (a > 255 ? 255 : (a < 0 ? 0 : a));
247 
248         return RGBA8(static_cast<uint8_t>(r), static_cast<uint8_t>(g), static_cast<uint8_t>(b),
249                      static_cast<uint8_t>(a));
250     }
251 
252     // Get the component-wise minimum of two colors
min(const RGBA8 & col1,const RGBA8 & col2)253     RGBA8 min(const RGBA8& col1, const RGBA8& col2) {
254         return RGBA8(std::min(col1.r, col2.r), std::min(col1.g, col2.g), std::min(col1.b, col2.b),
255                      std::min(col1.a, col2.a));
256     }
257 
258     // Get the component-wise maximum of two colors
max(const RGBA8 & col1,const RGBA8 & col2)259     RGBA8 max(const RGBA8& col1, const RGBA8& col2) {
260         return RGBA8(std::max(col1.r, col2.r), std::max(col1.g, col2.g), std::max(col1.b, col2.b),
261                      std::max(col1.a, col2.a));
262     }
263 
264     // Blend two RGBA8 color values parameterized by the provided factors in the range [0.f, 1.f]
mix(const RGBA8 & col1,const RGBA8 & col2,std::array<float,4> fac)265     RGBA8 mix(const RGBA8& col1, const RGBA8& col2, std::array<float, 4> fac) {
266         float r = static_cast<float>(col1.r) * (1.f - fac[0]) + static_cast<float>(col2.r) * fac[0];
267         float g = static_cast<float>(col1.g) * (1.f - fac[1]) + static_cast<float>(col2.g) * fac[1];
268         float b = static_cast<float>(col1.b) * (1.f - fac[2]) + static_cast<float>(col2.b) * fac[2];
269         float a = static_cast<float>(col1.a) * (1.f - fac[3]) + static_cast<float>(col2.a) * fac[3];
270 
271         return RGBA8({static_cast<uint8_t>(std::round(r)), static_cast<uint8_t>(std::round(g)),
272                       static_cast<uint8_t>(std::round(b)), static_cast<uint8_t>(std::round(a))});
273     }
274 
275     // Blend two RGBA8 color values parameterized by the provided RGBA8 factor
mix(const RGBA8 & col1,const RGBA8 & col2,const RGBA8 & fac)276     RGBA8 mix(const RGBA8& col1, const RGBA8& col2, const RGBA8& fac) {
277         std::array<float, 4> f = {{
278             static_cast<float>(fac.r) / 255.f,
279             static_cast<float>(fac.g) / 255.f,
280             static_cast<float>(fac.b) / 255.f,
281             static_cast<float>(fac.a) / 255.f,
282         }};
283         return mix(col1, col2, f);
284     }
285 
286     constexpr std::array<RGBA8, 8> kColors = {{
287         // check operations over multiple channels
288         RGBA8(64, 0, 0, 0),
289         RGBA8(0, 64, 0, 0),
290         RGBA8(64, 0, 32, 0),
291         RGBA8(0, 64, 32, 0),
292         RGBA8(128, 0, 128, 128),
293         RGBA8(0, 128, 128, 128),
294 
295         // check cases that may cause overflow
296         RGBA8(0, 0, 0, 0),
297         RGBA8(255, 255, 255, 255),
298     }};
299 }  // namespace
300 
301 // Test compilation and usage of the fixture
TEST_P(ColorStateTest,Basic)302 TEST_P(ColorStateTest, Basic) {
303     wgpu::BlendComponent blendComponent;
304     blendComponent.operation = wgpu::BlendOperation::Add;
305     blendComponent.srcFactor = wgpu::BlendFactor::One;
306     blendComponent.dstFactor = wgpu::BlendFactor::Zero;
307 
308     wgpu::BlendState blend;
309     blend.color = blendComponent;
310     blend.alpha = blendComponent;
311 
312     wgpu::ColorTargetState descriptor;
313     descriptor.blend = &blend;
314     descriptor.writeMask = wgpu::ColorWriteMask::All;
315 
316     SetupSingleSourcePipelines(descriptor);
317 
318     DoSingleSourceTest(RGBA8(0, 0, 0, 0), {RGBA8(255, 0, 0, 0)}, RGBA8(255, 0, 0, 0));
319 }
320 
321 // The following tests check test that the blend operation works
TEST_P(ColorStateTest,BlendOperationAdd)322 TEST_P(ColorStateTest, BlendOperationAdd) {
323     RGBA8 base(32, 64, 128, 192);
324     std::vector<std::pair<RGBA8, RGBA8>> tests;
325     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
326                    [&](const RGBA8& color) { return std::make_pair(color, base + color); });
327     CheckBlendOperation(base, wgpu::BlendOperation::Add, tests);
328 }
329 
TEST_P(ColorStateTest,BlendOperationSubtract)330 TEST_P(ColorStateTest, BlendOperationSubtract) {
331     RGBA8 base(32, 64, 128, 192);
332     std::vector<std::pair<RGBA8, RGBA8>> tests;
333     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
334                    [&](const RGBA8& color) { return std::make_pair(color, color - base); });
335     CheckBlendOperation(base, wgpu::BlendOperation::Subtract, tests);
336 }
337 
TEST_P(ColorStateTest,BlendOperationReverseSubtract)338 TEST_P(ColorStateTest, BlendOperationReverseSubtract) {
339     RGBA8 base(32, 64, 128, 192);
340     std::vector<std::pair<RGBA8, RGBA8>> tests;
341     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
342                    [&](const RGBA8& color) { return std::make_pair(color, base - color); });
343     CheckBlendOperation(base, wgpu::BlendOperation::ReverseSubtract, tests);
344 }
345 
TEST_P(ColorStateTest,BlendOperationMin)346 TEST_P(ColorStateTest, BlendOperationMin) {
347     RGBA8 base(32, 64, 128, 192);
348     std::vector<std::pair<RGBA8, RGBA8>> tests;
349     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
350                    [&](const RGBA8& color) { return std::make_pair(color, min(base, color)); });
351     CheckBlendOperation(base, wgpu::BlendOperation::Min, tests);
352 }
353 
TEST_P(ColorStateTest,BlendOperationMax)354 TEST_P(ColorStateTest, BlendOperationMax) {
355     RGBA8 base(32, 64, 128, 192);
356     std::vector<std::pair<RGBA8, RGBA8>> tests;
357     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
358                    [&](const RGBA8& color) { return std::make_pair(color, max(base, color)); });
359     CheckBlendOperation(base, wgpu::BlendOperation::Max, tests);
360 }
361 
362 // The following tests check that the Source blend factor works
TEST_P(ColorStateTest,SrcBlendFactorZero)363 TEST_P(ColorStateTest, SrcBlendFactorZero) {
364     RGBA8 base(32, 64, 128, 192);
365     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
366     std::transform(
367         kColors.begin(), kColors.end(), std::back_inserter(tests),
368         [&](const RGBA8& color) { return std::make_pair(TriangleSpec({{color}}), base); });
369     CheckSrcBlendFactor(base, wgpu::BlendFactor::Zero, wgpu::BlendFactor::Zero, tests);
370 }
371 
TEST_P(ColorStateTest,SrcBlendFactorOne)372 TEST_P(ColorStateTest, SrcBlendFactorOne) {
373     RGBA8 base(32, 64, 128, 192);
374     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
375     std::transform(
376         kColors.begin(), kColors.end(), std::back_inserter(tests),
377         [&](const RGBA8& color) { return std::make_pair(TriangleSpec({{color}}), base + color); });
378     CheckSrcBlendFactor(base, wgpu::BlendFactor::One, wgpu::BlendFactor::One, tests);
379 }
380 
TEST_P(ColorStateTest,SrcBlendFactorSrc)381 TEST_P(ColorStateTest, SrcBlendFactorSrc) {
382     RGBA8 base(32, 64, 128, 192);
383     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
384     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
385                    [&](const RGBA8& color) {
386                        RGBA8 fac = color;
387                        fac.a = 0;
388                        RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, fac);
389                        return std::make_pair(TriangleSpec({{color}}), expected);
390                    });
391     CheckSrcBlendFactor(base, wgpu::BlendFactor::Src, wgpu::BlendFactor::Zero, tests);
392 }
393 
TEST_P(ColorStateTest,SrcBlendFactorOneMinusSrc)394 TEST_P(ColorStateTest, SrcBlendFactorOneMinusSrc) {
395     RGBA8 base(32, 64, 128, 192);
396     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
397     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
398                    [&](const RGBA8& color) {
399                        RGBA8 fac = RGBA8(255, 255, 255, 255) - color;
400                        fac.a = 0;
401                        RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, fac);
402                        return std::make_pair(TriangleSpec({{color}}), expected);
403                    });
404     CheckSrcBlendFactor(base, wgpu::BlendFactor::OneMinusSrc, wgpu::BlendFactor::Zero, tests);
405 }
406 
TEST_P(ColorStateTest,SrcBlendFactorSrcAlpha)407 TEST_P(ColorStateTest, SrcBlendFactorSrcAlpha) {
408     RGBA8 base(32, 64, 128, 192);
409     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
410     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
411                    [&](const RGBA8& color) {
412                        RGBA8 fac(color.a, color.a, color.a, color.a);
413                        RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, fac);
414                        return std::make_pair(TriangleSpec({{color}}), expected);
415                    });
416     CheckSrcBlendFactor(base, wgpu::BlendFactor::SrcAlpha, wgpu::BlendFactor::SrcAlpha, tests);
417 }
418 
TEST_P(ColorStateTest,SrcBlendFactorOneMinusSrcAlpha)419 TEST_P(ColorStateTest, SrcBlendFactorOneMinusSrcAlpha) {
420     RGBA8 base(32, 64, 128, 192);
421     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
422     std::transform(
423         kColors.begin(), kColors.end(), std::back_inserter(tests), [&](const RGBA8& color) {
424             RGBA8 fac = RGBA8(255, 255, 255, 255) - RGBA8(color.a, color.a, color.a, color.a);
425             RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, fac);
426             return std::make_pair(TriangleSpec({{color}}), expected);
427         });
428     CheckSrcBlendFactor(base, wgpu::BlendFactor::OneMinusSrcAlpha,
429                         wgpu::BlendFactor::OneMinusSrcAlpha, tests);
430 }
431 
TEST_P(ColorStateTest,SrcBlendFactorDst)432 TEST_P(ColorStateTest, SrcBlendFactorDst) {
433     RGBA8 base(32, 64, 128, 192);
434     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
435     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
436                    [&](const RGBA8& color) {
437                        RGBA8 fac = base;
438                        fac.a = 0;
439                        RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, fac);
440                        return std::make_pair(TriangleSpec({{color}}), expected);
441                    });
442     CheckSrcBlendFactor(base, wgpu::BlendFactor::Dst, wgpu::BlendFactor::Zero, tests);
443 }
444 
TEST_P(ColorStateTest,SrcBlendFactorOneMinusDst)445 TEST_P(ColorStateTest, SrcBlendFactorOneMinusDst) {
446     RGBA8 base(32, 64, 128, 192);
447     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
448     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
449                    [&](const RGBA8& color) {
450                        RGBA8 fac = RGBA8(255, 255, 255, 255) - base;
451                        fac.a = 0;
452                        RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, fac);
453                        return std::make_pair(TriangleSpec({{color}}), expected);
454                    });
455     CheckSrcBlendFactor(base, wgpu::BlendFactor::OneMinusDst, wgpu::BlendFactor::Zero, tests);
456 }
457 
TEST_P(ColorStateTest,SrcBlendFactorDstAlpha)458 TEST_P(ColorStateTest, SrcBlendFactorDstAlpha) {
459     RGBA8 base(32, 64, 128, 192);
460     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
461     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
462                    [&](const RGBA8& color) {
463                        RGBA8 fac(base.a, base.a, base.a, base.a);
464                        RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, fac);
465                        return std::make_pair(TriangleSpec({{color}}), expected);
466                    });
467     CheckSrcBlendFactor(base, wgpu::BlendFactor::DstAlpha, wgpu::BlendFactor::DstAlpha, tests);
468 }
469 
TEST_P(ColorStateTest,SrcBlendFactorOneMinusDstAlpha)470 TEST_P(ColorStateTest, SrcBlendFactorOneMinusDstAlpha) {
471     RGBA8 base(32, 64, 128, 192);
472     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
473     std::transform(
474         kColors.begin(), kColors.end(), std::back_inserter(tests), [&](const RGBA8& color) {
475             RGBA8 fac = RGBA8(255, 255, 255, 255) - RGBA8(base.a, base.a, base.a, base.a);
476             RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, fac);
477             return std::make_pair(TriangleSpec({{color}}), expected);
478         });
479     CheckSrcBlendFactor(base, wgpu::BlendFactor::OneMinusDstAlpha,
480                         wgpu::BlendFactor::OneMinusDstAlpha, tests);
481 }
482 
TEST_P(ColorStateTest,SrcBlendFactorSrcAlphaSaturated)483 TEST_P(ColorStateTest, SrcBlendFactorSrcAlphaSaturated) {
484     RGBA8 base(32, 64, 128, 192);
485     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
486     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
487                    [&](const RGBA8& color) {
488                        uint8_t f = std::min(color.a, static_cast<uint8_t>(255 - base.a));
489                        RGBA8 fac(f, f, f, 255);
490                        RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, fac);
491                        return std::make_pair(TriangleSpec({{color}}), expected);
492                    });
493     CheckSrcBlendFactor(base, wgpu::BlendFactor::SrcAlphaSaturated,
494                         wgpu::BlendFactor::SrcAlphaSaturated, tests);
495 }
496 
TEST_P(ColorStateTest,SrcBlendFactorConstant)497 TEST_P(ColorStateTest, SrcBlendFactorConstant) {
498     RGBA8 base(32, 64, 128, 192);
499     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
500     std::transform(
501         kColors.begin(), kColors.end(), std::back_inserter(tests), [&](const RGBA8& color) {
502             auto triangleSpec = TriangleSpec({{color}, {{0.2f, 0.4f, 0.6f, 0.8f}}});
503             RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, triangleSpec.blendFactor);
504             return std::make_pair(triangleSpec, expected);
505         });
506     CheckSrcBlendFactor(base, wgpu::BlendFactor::Constant, wgpu::BlendFactor::Constant, tests);
507 }
508 
TEST_P(ColorStateTest,SrcBlendFactorOneMinusConstant)509 TEST_P(ColorStateTest, SrcBlendFactorOneMinusConstant) {
510     RGBA8 base(32, 64, 128, 192);
511     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
512     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
513                    [&](const RGBA8& color) {
514                        auto triangleSpec = TriangleSpec({{color}, {{0.2f, 0.4f, 0.6f, 0.8f}}});
515                        std::array<float, 4> f = {{0.8f, 0.6f, 0.4f, 0.2f}};
516                        RGBA8 expected = base + mix(RGBA8(0, 0, 0, 0), color, f);
517                        return std::make_pair(triangleSpec, expected);
518                    });
519     CheckSrcBlendFactor(base, wgpu::BlendFactor::OneMinusConstant,
520                         wgpu::BlendFactor::OneMinusConstant, tests);
521 }
522 
523 // The following tests check that the Destination blend factor works
TEST_P(ColorStateTest,DstBlendFactorZero)524 TEST_P(ColorStateTest, DstBlendFactorZero) {
525     RGBA8 base(32, 64, 128, 192);
526     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
527     std::transform(
528         kColors.begin(), kColors.end(), std::back_inserter(tests),
529         [&](const RGBA8& color) { return std::make_pair(TriangleSpec({{color}}), color); });
530     CheckDstBlendFactor(base, wgpu::BlendFactor::Zero, wgpu::BlendFactor::Zero, tests);
531 }
532 
TEST_P(ColorStateTest,DstBlendFactorOne)533 TEST_P(ColorStateTest, DstBlendFactorOne) {
534     RGBA8 base(32, 64, 128, 192);
535     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
536     std::transform(
537         kColors.begin(), kColors.end(), std::back_inserter(tests),
538         [&](const RGBA8& color) { return std::make_pair(TriangleSpec({{color}}), base + color); });
539     CheckDstBlendFactor(base, wgpu::BlendFactor::One, wgpu::BlendFactor::One, tests);
540 }
541 
TEST_P(ColorStateTest,DstBlendFactorSrc)542 TEST_P(ColorStateTest, DstBlendFactorSrc) {
543     RGBA8 base(32, 64, 128, 192);
544     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
545     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
546                    [&](const RGBA8& color) {
547                        RGBA8 fac = color;
548                        fac.a = 0;
549                        RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, fac);
550                        return std::make_pair(TriangleSpec({{color}}), expected);
551                    });
552     CheckDstBlendFactor(base, wgpu::BlendFactor::Src, wgpu::BlendFactor::Zero, tests);
553 }
554 
TEST_P(ColorStateTest,DstBlendFactorOneMinusSrc)555 TEST_P(ColorStateTest, DstBlendFactorOneMinusSrc) {
556     RGBA8 base(32, 64, 128, 192);
557     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
558     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
559                    [&](const RGBA8& color) {
560                        RGBA8 fac = RGBA8(255, 255, 255, 255) - color;
561                        fac.a = 0;
562                        RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, fac);
563                        return std::make_pair(TriangleSpec({{color}}), expected);
564                    });
565     CheckDstBlendFactor(base, wgpu::BlendFactor::OneMinusSrc, wgpu::BlendFactor::Zero, tests);
566 }
567 
TEST_P(ColorStateTest,DstBlendFactorSrcAlpha)568 TEST_P(ColorStateTest, DstBlendFactorSrcAlpha) {
569     RGBA8 base(32, 64, 128, 192);
570     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
571     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
572                    [&](const RGBA8& color) {
573                        RGBA8 fac(color.a, color.a, color.a, color.a);
574                        RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, fac);
575                        return std::make_pair(TriangleSpec({{color}}), expected);
576                    });
577     CheckDstBlendFactor(base, wgpu::BlendFactor::SrcAlpha, wgpu::BlendFactor::SrcAlpha, tests);
578 }
579 
TEST_P(ColorStateTest,DstBlendFactorOneMinusSrcAlpha)580 TEST_P(ColorStateTest, DstBlendFactorOneMinusSrcAlpha) {
581     RGBA8 base(32, 64, 128, 192);
582     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
583     std::transform(
584         kColors.begin(), kColors.end(), std::back_inserter(tests), [&](const RGBA8& color) {
585             RGBA8 fac = RGBA8(255, 255, 255, 255) - RGBA8(color.a, color.a, color.a, color.a);
586             RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, fac);
587             return std::make_pair(TriangleSpec({{color}}), expected);
588         });
589     CheckDstBlendFactor(base, wgpu::BlendFactor::OneMinusSrcAlpha,
590                         wgpu::BlendFactor::OneMinusSrcAlpha, tests);
591 }
592 
TEST_P(ColorStateTest,DstBlendFactorDst)593 TEST_P(ColorStateTest, DstBlendFactorDst) {
594     RGBA8 base(32, 64, 128, 192);
595     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
596     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
597                    [&](const RGBA8& color) {
598                        RGBA8 fac = base;
599                        fac.a = 0;
600                        RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, fac);
601                        return std::make_pair(TriangleSpec({{color}}), expected);
602                    });
603     CheckDstBlendFactor(base, wgpu::BlendFactor::Dst, wgpu::BlendFactor::Zero, tests);
604 }
605 
TEST_P(ColorStateTest,DstBlendFactorOneMinusDst)606 TEST_P(ColorStateTest, DstBlendFactorOneMinusDst) {
607     RGBA8 base(32, 64, 128, 192);
608     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
609     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
610                    [&](const RGBA8& color) {
611                        RGBA8 fac = RGBA8(255, 255, 255, 255) - base;
612                        fac.a = 0;
613                        RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, fac);
614                        return std::make_pair(TriangleSpec({{color}}), expected);
615                    });
616     CheckDstBlendFactor(base, wgpu::BlendFactor::OneMinusDst, wgpu::BlendFactor::Zero, tests);
617 }
618 
TEST_P(ColorStateTest,DstBlendFactorDstAlpha)619 TEST_P(ColorStateTest, DstBlendFactorDstAlpha) {
620     RGBA8 base(32, 64, 128, 192);
621     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
622     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
623                    [&](const RGBA8& color) {
624                        RGBA8 fac(base.a, base.a, base.a, base.a);
625                        RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, fac);
626                        return std::make_pair(TriangleSpec({{color}}), expected);
627                    });
628     CheckDstBlendFactor(base, wgpu::BlendFactor::DstAlpha, wgpu::BlendFactor::DstAlpha, tests);
629 }
630 
TEST_P(ColorStateTest,DstBlendFactorOneMinusDstAlpha)631 TEST_P(ColorStateTest, DstBlendFactorOneMinusDstAlpha) {
632     RGBA8 base(32, 64, 128, 192);
633     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
634     std::transform(
635         kColors.begin(), kColors.end(), std::back_inserter(tests), [&](const RGBA8& color) {
636             RGBA8 fac = RGBA8(255, 255, 255, 255) - RGBA8(base.a, base.a, base.a, base.a);
637             RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, fac);
638             return std::make_pair(TriangleSpec({{color}}), expected);
639         });
640     CheckDstBlendFactor(base, wgpu::BlendFactor::OneMinusDstAlpha,
641                         wgpu::BlendFactor::OneMinusDstAlpha, tests);
642 }
643 
TEST_P(ColorStateTest,DstBlendFactorSrcAlphaSaturated)644 TEST_P(ColorStateTest, DstBlendFactorSrcAlphaSaturated) {
645     RGBA8 base(32, 64, 128, 192);
646     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
647     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
648                    [&](const RGBA8& color) {
649                        uint8_t f = std::min(color.a, static_cast<uint8_t>(255 - base.a));
650                        RGBA8 fac(f, f, f, 255);
651                        RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, fac);
652                        return std::make_pair(TriangleSpec({{color}}), expected);
653                    });
654     CheckDstBlendFactor(base, wgpu::BlendFactor::SrcAlphaSaturated,
655                         wgpu::BlendFactor::SrcAlphaSaturated, tests);
656 }
657 
TEST_P(ColorStateTest,DstBlendFactorConstant)658 TEST_P(ColorStateTest, DstBlendFactorConstant) {
659     RGBA8 base(32, 64, 128, 192);
660     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
661     std::transform(
662         kColors.begin(), kColors.end(), std::back_inserter(tests), [&](const RGBA8& color) {
663             auto triangleSpec = TriangleSpec({{color}, {{0.2f, 0.4f, 0.6f, 0.8f}}});
664             RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, triangleSpec.blendFactor);
665             return std::make_pair(triangleSpec, expected);
666         });
667     CheckDstBlendFactor(base, wgpu::BlendFactor::Constant, wgpu::BlendFactor::Constant, tests);
668 }
669 
TEST_P(ColorStateTest,DstBlendFactorOneMinusConstant)670 TEST_P(ColorStateTest, DstBlendFactorOneMinusConstant) {
671     RGBA8 base(32, 64, 128, 192);
672     std::vector<std::pair<TriangleSpec, RGBA8>> tests;
673     std::transform(kColors.begin(), kColors.end(), std::back_inserter(tests),
674                    [&](const RGBA8& color) {
675                        auto triangleSpec = TriangleSpec({{color}, {{0.2f, 0.4f, 0.6f, 0.8f}}});
676                        std::array<float, 4> f = {{0.8f, 0.6f, 0.4f, 0.2f}};
677                        RGBA8 expected = color + mix(RGBA8(0, 0, 0, 0), base, f);
678                        return std::make_pair(triangleSpec, expected);
679                    });
680     CheckDstBlendFactor(base, wgpu::BlendFactor::OneMinusConstant,
681                         wgpu::BlendFactor::OneMinusConstant, tests);
682 }
683 
684 // Check that the color write mask works
TEST_P(ColorStateTest,ColorWriteMask)685 TEST_P(ColorStateTest, ColorWriteMask) {
686     wgpu::BlendComponent blendComponent;
687     blendComponent.operation = wgpu::BlendOperation::Add;
688     blendComponent.srcFactor = wgpu::BlendFactor::One;
689     blendComponent.dstFactor = wgpu::BlendFactor::One;
690 
691     wgpu::BlendState blend;
692     blend.color = blendComponent;
693     blend.alpha = blendComponent;
694 
695     wgpu::ColorTargetState descriptor;
696     descriptor.blend = &blend;
697     {
698         // Test single channel color write
699         descriptor.writeMask = wgpu::ColorWriteMask::Red;
700         SetupSingleSourcePipelines(descriptor);
701 
702         RGBA8 base(32, 64, 128, 192);
703         for (auto& color : kColors) {
704             RGBA8 expected = base + RGBA8(color.r, 0, 0, 0);
705             DoSingleSourceTest(base, {color}, expected);
706         }
707     }
708 
709     {
710         // Test multi channel color write
711         descriptor.writeMask = wgpu::ColorWriteMask::Green | wgpu::ColorWriteMask::Alpha;
712         SetupSingleSourcePipelines(descriptor);
713 
714         RGBA8 base(32, 64, 128, 192);
715         for (auto& color : kColors) {
716             RGBA8 expected = base + RGBA8(0, color.g, 0, color.a);
717             DoSingleSourceTest(base, {color}, expected);
718         }
719     }
720 
721     {
722         // Test no channel color write
723         descriptor.writeMask = wgpu::ColorWriteMask::None;
724         SetupSingleSourcePipelines(descriptor);
725 
726         RGBA8 base(32, 64, 128, 192);
727         for (auto& color : kColors) {
728             DoSingleSourceTest(base, {color}, base);
729         }
730     }
731 }
732 
733 // Check that the color write mask works when blending is disabled
TEST_P(ColorStateTest,ColorWriteMaskBlendingDisabled)734 TEST_P(ColorStateTest, ColorWriteMaskBlendingDisabled) {
735     {
736         wgpu::BlendComponent blendComponent;
737         blendComponent.operation = wgpu::BlendOperation::Add;
738         blendComponent.srcFactor = wgpu::BlendFactor::One;
739         blendComponent.dstFactor = wgpu::BlendFactor::Zero;
740 
741         wgpu::BlendState blend;
742         blend.color = blendComponent;
743         blend.alpha = blendComponent;
744 
745         wgpu::ColorTargetState descriptor;
746         descriptor.blend = &blend;
747         descriptor.writeMask = wgpu::ColorWriteMask::Red;
748         SetupSingleSourcePipelines(descriptor);
749 
750         RGBA8 base(32, 64, 128, 192);
751         RGBA8 expected(32, 0, 0, 0);
752 
753         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
754         {
755             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
756             pass.SetPipeline(testPipeline);
757             pass.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({{base}})));
758             pass.Draw(3);
759             pass.EndPass();
760         }
761 
762         wgpu::CommandBuffer commands = encoder.Finish();
763         queue.Submit(1, &commands);
764         EXPECT_PIXEL_RGBA8_EQ(expected, renderPass.color, kRTSize / 2, kRTSize / 2);
765     }
766 }
767 
768 // Test that independent color states on render targets works
TEST_P(ColorStateTest,IndependentColorState)769 TEST_P(ColorStateTest, IndependentColorState) {
770     DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_indexed_draw_buffers"));
771 
772     std::array<wgpu::Texture, 4> renderTargets;
773     std::array<wgpu::TextureView, 4> renderTargetViews;
774 
775     wgpu::TextureDescriptor descriptor;
776     descriptor.dimension = wgpu::TextureDimension::e2D;
777     descriptor.size.width = kRTSize;
778     descriptor.size.height = kRTSize;
779     descriptor.size.depthOrArrayLayers = 1;
780     descriptor.sampleCount = 1;
781     descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
782     descriptor.mipLevelCount = 1;
783     descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
784 
785     for (uint32_t i = 0; i < 4; ++i) {
786         renderTargets[i] = device.CreateTexture(&descriptor);
787         renderTargetViews[i] = renderTargets[i].CreateView();
788     }
789 
790     utils::ComboRenderPassDescriptor renderPass(
791         {renderTargetViews[0], renderTargetViews[1], renderTargetViews[2], renderTargetViews[3]});
792 
793     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
794         [[block]] struct MyBlock {
795             color0 : vec4<f32>;
796             color1 : vec4<f32>;
797             color2 : vec4<f32>;
798             color3 : vec4<f32>;
799         };
800 
801         [[group(0), binding(0)]] var<uniform> myUbo : MyBlock;
802 
803         struct FragmentOut {
804             [[location(0)]] fragColor0 : vec4<f32>;
805             [[location(1)]] fragColor1 : vec4<f32>;
806             [[location(2)]] fragColor2 : vec4<f32>;
807             [[location(3)]] fragColor3 : vec4<f32>;
808         };
809 
810         [[stage(fragment)]] fn main() -> FragmentOut {
811             var output : FragmentOut;
812             output.fragColor0 = myUbo.color0;
813             output.fragColor1 = myUbo.color1;
814             output.fragColor2 = myUbo.color2;
815             output.fragColor3 = myUbo.color3;
816             return output;
817         }
818     )");
819 
820     utils::ComboRenderPipelineDescriptor baseDescriptor;
821     baseDescriptor.layout = pipelineLayout;
822     baseDescriptor.vertex.module = vsModule;
823     baseDescriptor.cFragment.module = fsModule;
824     baseDescriptor.cFragment.targetCount = 4;
825 
826     basePipeline = device.CreateRenderPipeline(&baseDescriptor);
827 
828     utils::ComboRenderPipelineDescriptor testDescriptor;
829     testDescriptor.layout = pipelineLayout;
830     testDescriptor.vertex.module = vsModule;
831     testDescriptor.cFragment.module = fsModule;
832     testDescriptor.cFragment.targetCount = 4;
833 
834     // set color states
835     wgpu::BlendComponent blendComponent0;
836     blendComponent0.operation = wgpu::BlendOperation::Add;
837     blendComponent0.srcFactor = wgpu::BlendFactor::One;
838     blendComponent0.dstFactor = wgpu::BlendFactor::One;
839 
840     wgpu::BlendState blend0;
841     blend0.color = blendComponent0;
842     blend0.alpha = blendComponent0;
843 
844     wgpu::BlendComponent blendComponent1;
845     blendComponent1.operation = wgpu::BlendOperation::Subtract;
846     blendComponent1.srcFactor = wgpu::BlendFactor::One;
847     blendComponent1.dstFactor = wgpu::BlendFactor::One;
848 
849     wgpu::BlendState blend1;
850     blend1.color = blendComponent1;
851     blend1.alpha = blendComponent1;
852 
853     // Blend state intentionally omitted for target 2
854 
855     wgpu::BlendComponent blendComponent3;
856     blendComponent3.operation = wgpu::BlendOperation::Min;
857     blendComponent3.srcFactor = wgpu::BlendFactor::One;
858     blendComponent3.dstFactor = wgpu::BlendFactor::One;
859 
860     wgpu::BlendState blend3;
861     blend3.color = blendComponent3;
862     blend3.alpha = blendComponent3;
863 
864     testDescriptor.cTargets[0].blend = &blend0;
865     testDescriptor.cTargets[1].blend = &blend1;
866     testDescriptor.cTargets[3].blend = &blend3;
867 
868     testPipeline = device.CreateRenderPipeline(&testDescriptor);
869 
870     for (unsigned int c = 0; c < kColors.size(); ++c) {
871         RGBA8 base = kColors[((c + 31) * 29) % kColors.size()];
872         RGBA8 color0 = kColors[((c + 19) * 13) % kColors.size()];
873         RGBA8 color1 = kColors[((c + 11) * 43) % kColors.size()];
874         RGBA8 color2 = kColors[((c + 7) * 3) % kColors.size()];
875         RGBA8 color3 = kColors[((c + 13) * 71) % kColors.size()];
876 
877         RGBA8 expected0 = color0 + base;
878         RGBA8 expected1 = color1 - base;
879         RGBA8 expected2 = color2;
880         RGBA8 expected3 = min(color3, base);
881 
882         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
883         {
884             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
885             pass.SetPipeline(basePipeline);
886             pass.SetBindGroup(
887                 0, MakeBindGroupForColors(std::array<RGBA8, 4>({{base, base, base, base}})));
888             pass.Draw(3);
889 
890             pass.SetPipeline(testPipeline);
891             pass.SetBindGroup(0, MakeBindGroupForColors(
892                                      std::array<RGBA8, 4>({{color0, color1, color2, color3}})));
893             pass.Draw(3);
894             pass.EndPass();
895         }
896 
897         wgpu::CommandBuffer commands = encoder.Finish();
898         queue.Submit(1, &commands);
899 
900         EXPECT_PIXEL_RGBA8_EQ(expected0, renderTargets[0], kRTSize / 2, kRTSize / 2)
901             << "Attachment slot 0 should have been " << color0 << " + " << base << " = "
902             << expected0;
903         EXPECT_PIXEL_RGBA8_EQ(expected1, renderTargets[1], kRTSize / 2, kRTSize / 2)
904             << "Attachment slot 1 should have been " << color1 << " - " << base << " = "
905             << expected1;
906         EXPECT_PIXEL_RGBA8_EQ(expected2, renderTargets[2], kRTSize / 2, kRTSize / 2)
907             << "Attachment slot 2 should have been " << color2 << " = " << expected2
908             << "(no blending)";
909         EXPECT_PIXEL_RGBA8_EQ(expected3, renderTargets[3], kRTSize / 2, kRTSize / 2)
910             << "Attachment slot 3 should have been min(" << color3 << ", " << base
911             << ") = " << expected3;
912     }
913 }
914 
915 // Test that the default blend color is correctly set at the beginning of every subpass
TEST_P(ColorStateTest,DefaultBlendColor)916 TEST_P(ColorStateTest, DefaultBlendColor) {
917     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
918         [[block]] struct MyBlock {
919             color : vec4<f32>;
920         };
921 
922         [[group(0), binding(0)]] var<uniform> myUbo : MyBlock;
923 
924         [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
925             return myUbo.color;
926         }
927     )");
928 
929     utils::ComboRenderPipelineDescriptor baseDescriptor;
930     baseDescriptor.layout = pipelineLayout;
931     baseDescriptor.vertex.module = vsModule;
932     baseDescriptor.cFragment.module = fsModule;
933     baseDescriptor.cTargets[0].format = renderPass.colorFormat;
934 
935     basePipeline = device.CreateRenderPipeline(&baseDescriptor);
936 
937     utils::ComboRenderPipelineDescriptor testDescriptor;
938     testDescriptor.layout = pipelineLayout;
939     testDescriptor.vertex.module = vsModule;
940     testDescriptor.cFragment.module = fsModule;
941     testDescriptor.cTargets[0].format = renderPass.colorFormat;
942 
943     wgpu::BlendComponent blendComponent;
944     blendComponent.operation = wgpu::BlendOperation::Add;
945     blendComponent.srcFactor = wgpu::BlendFactor::Constant;
946     blendComponent.dstFactor = wgpu::BlendFactor::One;
947 
948     wgpu::BlendState blend;
949     blend.color = blendComponent;
950     blend.alpha = blendComponent;
951 
952     testDescriptor.cTargets[0].blend = &blend;
953 
954     testPipeline = device.CreateRenderPipeline(&testDescriptor);
955     constexpr wgpu::Color kWhite{1.0f, 1.0f, 1.0f, 1.0f};
956 
957     // Check that the initial blend color is (0,0,0,0)
958     {
959         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
960         {
961             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
962             pass.SetPipeline(basePipeline);
963             pass.SetBindGroup(0,
964                               MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(0, 0, 0, 0)}})));
965             pass.Draw(3);
966             pass.SetPipeline(testPipeline);
967             pass.SetBindGroup(
968                 0, MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(255, 255, 255, 255)}})));
969             pass.Draw(3);
970             pass.EndPass();
971         }
972 
973         wgpu::CommandBuffer commands = encoder.Finish();
974         queue.Submit(1, &commands);
975 
976         EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, kRTSize / 2, kRTSize / 2);
977     }
978 
979     // Check that setting the blend color works
980     {
981         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
982         {
983             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
984             pass.SetPipeline(basePipeline);
985             pass.SetBindGroup(0,
986                               MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(0, 0, 0, 0)}})));
987             pass.Draw(3);
988             pass.SetPipeline(testPipeline);
989             pass.SetBlendConstant(&kWhite);
990             pass.SetBindGroup(
991                 0, MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(255, 255, 255, 255)}})));
992             pass.Draw(3);
993             pass.EndPass();
994         }
995 
996         wgpu::CommandBuffer commands = encoder.Finish();
997         queue.Submit(1, &commands);
998 
999         EXPECT_PIXEL_RGBA8_EQ(RGBA8(255, 255, 255, 255), renderPass.color, kRTSize / 2,
1000                               kRTSize / 2);
1001     }
1002 
1003     // Check that the blend color is not inherited between render passes
1004     {
1005         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1006         {
1007             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
1008             pass.SetPipeline(basePipeline);
1009             pass.SetBindGroup(0,
1010                               MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(0, 0, 0, 0)}})));
1011             pass.Draw(3);
1012             pass.SetPipeline(testPipeline);
1013             pass.SetBlendConstant(&kWhite);
1014             pass.SetBindGroup(
1015                 0, MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(255, 255, 255, 255)}})));
1016             pass.Draw(3);
1017             pass.EndPass();
1018         }
1019         {
1020             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
1021             pass.SetPipeline(basePipeline);
1022             pass.SetBindGroup(0,
1023                               MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(0, 0, 0, 0)}})));
1024             pass.Draw(3);
1025             pass.SetPipeline(testPipeline);
1026             pass.SetBindGroup(
1027                 0, MakeBindGroupForColors(std::array<RGBA8, 1>({{RGBA8(255, 255, 255, 255)}})));
1028             pass.Draw(3);
1029             pass.EndPass();
1030         }
1031 
1032         wgpu::CommandBuffer commands = encoder.Finish();
1033         queue.Submit(1, &commands);
1034 
1035         EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, kRTSize / 2, kRTSize / 2);
1036     }
1037 }
1038 
1039 // This tests a problem in the OpenGL backend where a previous color write mask
1040 // persisted and prevented a render pass loadOp from fully clearing the output
1041 // attachment.
TEST_P(ColorStateTest,ColorWriteMaskDoesNotAffectRenderPassLoadOpClear)1042 TEST_P(ColorStateTest, ColorWriteMaskDoesNotAffectRenderPassLoadOpClear) {
1043     wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
1044         [[block]] struct MyBlock {
1045             color : vec4<f32>;
1046         };
1047 
1048         [[group(0), binding(0)]] var<uniform> myUbo : MyBlock;
1049 
1050         [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
1051             return myUbo.color;
1052         }
1053     )");
1054 
1055     utils::ComboRenderPipelineDescriptor baseDescriptor;
1056     baseDescriptor.layout = pipelineLayout;
1057     baseDescriptor.vertex.module = vsModule;
1058     baseDescriptor.cFragment.module = fsModule;
1059     baseDescriptor.cTargets[0].format = renderPass.colorFormat;
1060 
1061     basePipeline = device.CreateRenderPipeline(&baseDescriptor);
1062 
1063     utils::ComboRenderPipelineDescriptor testDescriptor;
1064     testDescriptor.layout = pipelineLayout;
1065     testDescriptor.vertex.module = vsModule;
1066     testDescriptor.cFragment.module = fsModule;
1067     testDescriptor.cTargets[0].format = renderPass.colorFormat;
1068     testDescriptor.cTargets[0].writeMask = wgpu::ColorWriteMask::Red;
1069 
1070     testPipeline = device.CreateRenderPipeline(&testDescriptor);
1071 
1072     RGBA8 base(32, 64, 128, 192);
1073     RGBA8 expected(0, 0, 0, 0);
1074 
1075     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1076     {
1077         // Clear the render attachment to |base|
1078         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
1079         pass.SetPipeline(basePipeline);
1080         pass.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({{base}})));
1081         pass.Draw(3);
1082 
1083         // Set a pipeline that will dirty the color write mask
1084         pass.SetPipeline(testPipeline);
1085         pass.EndPass();
1086     }
1087     {
1088         // This renderpass' loadOp should clear all channels of the render attachment
1089         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
1090         pass.EndPass();
1091     }
1092     wgpu::CommandBuffer commands = encoder.Finish();
1093     queue.Submit(1, &commands);
1094 
1095     EXPECT_PIXEL_RGBA8_EQ(expected, renderPass.color, kRTSize / 2, kRTSize / 2);
1096 }
1097 
1098 DAWN_INSTANTIATE_TEST(ColorStateTest,
1099                       D3D12Backend(),
1100                       MetalBackend(),
1101                       OpenGLBackend(),
1102                       OpenGLESBackend(),
1103                       VulkanBackend());
1104