diff --git a/src/backend/d3d12/CommandBufferD3D12.cpp b/src/backend/d3d12/CommandBufferD3D12.cpp index 5629d3fde7..eec4db7bf6 100644 --- a/src/backend/d3d12/CommandBufferD3D12.cpp +++ b/src/backend/d3d12/CommandBufferD3D12.cpp @@ -278,6 +278,9 @@ namespace d3d12 { } else { commandList->OMSetRenderTargets(args.numRTVs, args.RTVs, FALSE, nullptr); } + + static constexpr std::array defaultBlendFactor = { 0, 0, 0, 0 }; + commandList->OMSetBlendFactor(&defaultBlendFactor[0]); } break; @@ -398,7 +401,6 @@ namespace d3d12 { case Command::DrawArrays: { DrawArraysCmd* draw = commands.NextCommand(); - commandList->DrawInstanced( draw->vertexCount, draw->instanceCount, diff --git a/src/backend/opengl/CommandBufferGL.cpp b/src/backend/opengl/CommandBufferGL.cpp index 00c04f092a..2668f794b2 100644 --- a/src/backend/opengl/CommandBufferGL.cpp +++ b/src/backend/opengl/CommandBufferGL.cpp @@ -148,6 +148,8 @@ namespace opengl { glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } + + glBlendColor(0, 0, 0, 0); } break; diff --git a/src/tests/end2end/BlendStateTests.cpp b/src/tests/end2end/BlendStateTests.cpp index 90e4684f1a..d9407afa39 100644 --- a/src/tests/end2end/BlendStateTests.cpp +++ b/src/tests/end2end/BlendStateTests.cpp @@ -837,4 +837,139 @@ TEST_P(BlendStateTest, IndependentBlendState) { } } +TEST_P(BlendStateTest, DefaultBlendColor) { + nxt::BlendState blendState = device.CreateBlendStateBuilder() + .SetBlendEnabled(true) + .SetColorBlend(nxt::BlendOperation::Add, nxt::BlendFactor::BlendColor, nxt::BlendFactor::One) + .SetAlphaBlend(nxt::BlendOperation::Add, nxt::BlendFactor::BlendColor, nxt::BlendFactor::One) + .GetResult(); + + renderpass = device.CreateRenderPassBuilder() + .SetAttachmentCount(1) + .SetSubpassCount(2) + .AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm) + .SubpassSetColorAttachment(0, 0, 0) + .SubpassSetColorAttachment(1, 0, 0) + .GetResult(); + + framebuffer = device.CreateFramebufferBuilder() + .SetRenderPass(renderpass) + .SetDimensions(kRTSize, kRTSize) + .SetAttachment(0, renderTargetView) + .GetResult(); + + nxt::ShaderModule fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"( + #version 450 + layout(set = 0, binding = 0) uniform myBlock { + vec4 color; + } myUbo; + + layout(location = 0) out vec4 fragColor; + + void main() { + fragColor = myUbo.color; + } + )"); + + basePipeline = device.CreateRenderPipelineBuilder() + .SetSubpass(renderpass, 0) + .SetLayout(pipelineLayout) + .SetStage(nxt::ShaderStage::Vertex, vsModule, "main") + .SetStage(nxt::ShaderStage::Fragment, fsModule, "main") + .GetResult(); + + testPipeline = device.CreateRenderPipelineBuilder() + .SetSubpass(renderpass, 0) + .SetLayout(pipelineLayout) + .SetStage(nxt::ShaderStage::Vertex, vsModule, "main") + .SetStage(nxt::ShaderStage::Fragment, fsModule, "main") + .SetColorAttachmentBlendState(0, blendState) + .GetResult(); + + nxt::RenderPipeline basePipeline2 = device.CreateRenderPipelineBuilder() + .SetSubpass(renderpass, 1) + .SetLayout(pipelineLayout) + .SetStage(nxt::ShaderStage::Vertex, vsModule, "main") + .SetStage(nxt::ShaderStage::Fragment, fsModule, "main") + .GetResult(); + + nxt::RenderPipeline testPipeline2 = device.CreateRenderPipelineBuilder() + .SetSubpass(renderpass, 1) + .SetLayout(pipelineLayout) + .SetStage(nxt::ShaderStage::Vertex, vsModule, "main") + .SetStage(nxt::ShaderStage::Fragment, fsModule, "main") + .SetColorAttachmentBlendState(0, blendState) + .GetResult(); + + // Check that the initial blend color is (0,0,0,0) + { + nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() + .BeginRenderPass(renderpass, framebuffer) + .BeginRenderSubpass() + .SetRenderPipeline(basePipeline) + .SetBindGroup(0, MakeBindGroupForColors(std::array({ { RGBA8(0, 0, 0, 0) } }))) + .DrawArrays(3, 1, 0, 0) + .SetRenderPipeline(testPipeline) + .SetBindGroup(0, MakeBindGroupForColors(std::array({ { RGBA8(255, 255, 255, 255) } }))) + .DrawArrays(3, 1, 0, 0) + .EndRenderSubpass() + .EndRenderPass() + .GetResult(); + + queue.Submit(1, &commands); + + EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderTarget, kRTSize / 2, kRTSize / 2); + } + + // Check that setting the blend color works + { + nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() + .BeginRenderPass(renderpass, framebuffer) + .BeginRenderSubpass() + .SetRenderPipeline(basePipeline) + .SetBindGroup(0, MakeBindGroupForColors(std::array({ { RGBA8(0, 0, 0, 0) } }))) + .DrawArrays(3, 1, 0, 0) + .SetRenderPipeline(testPipeline) + .SetBlendColor(1, 1, 1, 1) + .SetBindGroup(0, MakeBindGroupForColors(std::array({ { RGBA8(255, 255, 255, 255) } }))) + .DrawArrays(3, 1, 0, 0) + .EndRenderSubpass() + .EndRenderPass() + .GetResult(); + + queue.Submit(1, &commands); + + EXPECT_PIXEL_RGBA8_EQ(RGBA8(255, 255, 255, 255), renderTarget, kRTSize / 2, kRTSize / 2); + } + + // Check that the blend color is not inherited + { + nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() + .BeginRenderPass(renderpass, framebuffer) + .BeginRenderSubpass() + .SetRenderPipeline(basePipeline) + .SetBindGroup(0, MakeBindGroupForColors(std::array({ { RGBA8(0, 0, 0, 0) } }))) + .DrawArrays(3, 1, 0, 0) + .SetRenderPipeline(testPipeline) + .SetBlendColor(1, 1, 1, 1) + .SetBindGroup(0, MakeBindGroupForColors(std::array({ { RGBA8(255, 255, 255, 255) } }))) + .DrawArrays(3, 1, 0, 0) + .EndRenderSubpass() + .BeginRenderSubpass() + .SetRenderPipeline(basePipeline2) + .SetBindGroup(0, MakeBindGroupForColors(std::array({ { RGBA8(0, 0, 0, 0) } }))) + .DrawArrays(3, 1, 0, 0) + .SetRenderPipeline(testPipeline2) + .SetBindGroup(0, MakeBindGroupForColors(std::array({ { RGBA8(255, 255, 255, 255) } }))) + .DrawArrays(3, 1, 0, 0) + .EndRenderSubpass() + .EndRenderPass() + .GetResult(); + + queue.Submit(1, &commands); + + EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderTarget, kRTSize / 2, kRTSize / 2); + } +} + NXT_INSTANTIATE_TEST(BlendStateTest, D3D12Backend, MetalBackend, OpenGLBackend)