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