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