diff --git a/include/boo/graphicsdev/D3D.hpp b/include/boo/graphicsdev/D3D.hpp index 00f53cf..c3108fb 100644 --- a/include/boo/graphicsdev/D3D.hpp +++ b/include/boo/graphicsdev/D3D.hpp @@ -35,7 +35,7 @@ public: const boo::ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling)=0; + bool alphaWrite, CullMode culling, bool overwriteAlpha=true)=0; }; }; diff --git a/include/boo/graphicsdev/GL.hpp b/include/boo/graphicsdev/GL.hpp index a53dd60..c079228 100644 --- a/include/boo/graphicsdev/GL.hpp +++ b/include/boo/graphicsdev/GL.hpp @@ -52,7 +52,7 @@ public: size_t uniformBlockCount, const char** uniformBlockNames, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling); + bool alphaWrite, CullMode culling, bool overwriteAlpha = true); ObjToken newShaderDataBinding(const ObjToken& pipeline, diff --git a/include/boo/graphicsdev/Metal.hpp b/include/boo/graphicsdev/Metal.hpp index 5768264..6eb7538 100644 --- a/include/boo/graphicsdev/Metal.hpp +++ b/include/boo/graphicsdev/Metal.hpp @@ -48,7 +48,9 @@ public: const ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling, bool depthAttachment = true); + bool alphaWrite, CullMode culling, + bool overwriteAlpha = true, + bool depthAttachment = true); ObjToken newShaderDataBinding(const ObjToken& pipeline, diff --git a/include/boo/graphicsdev/Vulkan.hpp b/include/boo/graphicsdev/Vulkan.hpp index f02c343..c3ee311 100644 --- a/include/boo/graphicsdev/Vulkan.hpp +++ b/include/boo/graphicsdev/Vulkan.hpp @@ -160,7 +160,7 @@ public: const boo::ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling); + bool alphaWrite, CullMode culling, bool overwriteAlpha = true); boo::ObjToken newShaderPipeline(const char* vertSource, const char* fragSource, const boo::ObjToken& vtxFmt, diff --git a/lib/graphicsdev/D3D11.cpp b/lib/graphicsdev/D3D11.cpp index a7afbcf..dc133c4 100644 --- a/lib/graphicsdev/D3D11.cpp +++ b/lib/graphicsdev/D3D11.cpp @@ -560,7 +560,7 @@ class D3D11ShaderPipeline : public GraphicsDataNode const boo::ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling) + bool alphaWrite, bool overwriteAlpha, CullMode culling) : GraphicsDataNode(parent), m_vtxFmt(vtxFmt), m_vert(std::move(vert)), m_pixel(std::move(pixel)), m_topology(PRIMITIVE_TABLE[int(prim)]) @@ -619,15 +619,36 @@ class D3D11ShaderPipeline : public GraphicsDataNode blDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; blDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; blDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_REV_SUBTRACT; + if (overwriteAlpha) + { + blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + } + else + { + blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; + blDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_REV_SUBTRACT; + } } else { blDesc.RenderTarget[0].SrcBlend = BLEND_FACTOR_TABLE[int(srcFac)]; blDesc.RenderTarget[0].DestBlend = BLEND_FACTOR_TABLE[int(dstFac)]; blDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + if (m_overwriteAlpha) + { + blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + } + else + { + blDesc.RenderTarget[0].SrcBlendAlpha = BLEND_FACTOR_TABLE[int(srcFac)]; + blDesc.RenderTarget[0].DestBlendAlpha = BLEND_FACTOR_TABLE[int(dstFac)]; + } + blDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; } - blDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; blDesc.RenderTarget[0].RenderTargetWriteMask = (colorWrite ? (D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | @@ -1381,7 +1402,7 @@ public: ComPtr* pipelineBlob, const boo::ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling) + bool alphaWrite, CullMode culling, bool overwriteAlpha) { XXH64_state_t hashState; uint64_t srcHashes[2] = {}; @@ -1482,7 +1503,8 @@ public: return {new D3D11ShaderPipeline(m_data, ctx, std::move(vertShader), std::move(fragShader), - vtxFmt, srcFac, dstFac, prim, depthTest, depthWrite, colorWrite, alphaWrite, culling)}; + vtxFmt, srcFac, dstFac, prim, depthTest, depthWrite, colorWrite, + alphaWrite, overwriteAlpha, culling)}; } boo::ObjToken newShaderDataBinding( diff --git a/lib/graphicsdev/D3D12.cpp b/lib/graphicsdev/D3D12.cpp index 2460725..c2cd608 100644 --- a/lib/graphicsdev/D3D12.cpp +++ b/lib/graphicsdev/D3D12.cpp @@ -751,15 +751,36 @@ class D3D12ShaderPipeline : public GraphicsDataNode desc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; desc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_ONE; desc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_REV_SUBTRACT; + if (overwriteAlpha) + { + desc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; + desc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; + desc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + } + else + { + desc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; + desc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE; + desc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_REV_SUBTRACT; + } } else { desc.BlendState.RenderTarget[0].SrcBlend = BLEND_FACTOR_TABLE[int(srcFac)]; desc.BlendState.RenderTarget[0].DestBlend = BLEND_FACTOR_TABLE[int(dstFac)]; desc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + if (m_overwriteAlpha) + { + desc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; + desc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; + } + else + { + desc.BlendState.RenderTarget[0].SrcBlendAlpha = BLEND_FACTOR_TABLE[int(srcFac)]; + desc.BlendState.RenderTarget[0].DestBlendAlpha = BLEND_FACTOR_TABLE[int(dstFac)]; + } + desc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; } - desc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE; - desc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; } desc.BlendState.RenderTarget[0].RenderTargetWriteMask = (colorWrite ? (D3D12_COLOR_WRITE_ENABLE_RED | @@ -1846,7 +1867,7 @@ public: ComPtr* pipelineBlob, const boo::ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling) + bool alphaWrite, CullMode culling, bool overwriteAlpha) { XXH64_state_t hashState; uint64_t srcHashes[2] = {}; @@ -1930,9 +1951,10 @@ public: } ID3DBlob* pipeline = pipelineBlob ? pipelineBlob->Get() : nullptr; - D3D12ShaderPipeline* retval = new D3D12ShaderPipeline(m_data, m_parent.m_ctx, std::move(vertShader), std::move(fragShader), - pipeline, vtxFmt, srcFac, dstFac, prim, depthTest, depthWrite, colorWrite, - alphaWrite, culling); + D3D12ShaderPipeline* retval = new D3D12ShaderPipeline( + m_data, m_parent.m_ctx, std::move(vertShader), std::move(fragShader), + pipeline, vtxFmt, srcFac, dstFac, prim, depthTest, depthWrite, colorWrite, + alphaWrite, overwriteAlpha, culling); if (pipelineBlob && !*pipelineBlob) retval->m_state->GetCachedBlob(&*pipelineBlob); return retval; diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index 3cd43be..96964a5 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -669,6 +669,7 @@ class GLShaderPipeline : public GraphicsDataNode bool m_colorWrite = true; bool m_alphaWrite = true; bool m_subtractBlend = false; + bool m_overwriteAlpha = false; CullMode m_culling; mutable std::vector m_uniLocs; mutable std::vector m_texNames; @@ -748,9 +749,13 @@ public: if (m_dfactor != GL_ZERO) { glEnable(GL_BLEND); - glBlendFuncSeparate(m_sfactor, m_dfactor, GL_ONE, GL_ZERO); + if (m_overwriteAlpha) + glBlendFuncSeparate(m_sfactor, m_dfactor, GL_ONE, GL_ZERO); + else + glBlendFuncSeparate(m_sfactor, m_dfactor, m_sfactor, m_dfactor); if (m_subtractBlend) - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendEquationSeparate(GL_FUNC_REVERSE_SUBTRACT, + m_overwriteAlpha ? GL_FUNC_ADD : GL_FUNC_REVERSE_SUBTRACT); else glBlendEquation(GL_FUNC_ADD); } @@ -822,7 +827,7 @@ ObjToken GLDataFactory::Context::newShaderPipeline size_t uniformBlockCount, const char** uniformBlockNames, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling) + bool alphaWrite, CullMode culling, bool overwriteAlpha) { GLDataFactoryImpl& factory = static_cast(m_parent); ObjToken retval(new GLShaderPipeline(m_data)); @@ -928,6 +933,7 @@ ObjToken GLDataFactory::Context::newShaderPipeline shader.m_depthWrite = depthWrite; shader.m_colorWrite = colorWrite; shader.m_alphaWrite = alphaWrite; + shader.m_overwriteAlpha = overwriteAlpha; shader.m_culling = culling; shader.m_drawPrim = PRIMITIVE_TABLE[int(prim)]; diff --git a/lib/graphicsdev/Metal.mm b/lib/graphicsdev/Metal.mm index 06bf029..2700ac7 100644 --- a/lib/graphicsdev/Metal.mm +++ b/lib/graphicsdev/Metal.mm @@ -99,7 +99,7 @@ class MetalDataFactoryImpl : public MetalDataFactory, public GraphicsDataFactory m_gammaVFMT = ctx.newVertexFormat(2, vfmt); m_gammaShader = static_cast(ctx).newShaderPipeline(GammaVS, GammaFS, nullptr, nullptr, m_gammaVFMT, BlendFactor::One, BlendFactor::Zero, - Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None, false); + Primitive::TriStrips, ZTest::None, false, true, false, CullMode::None, true, false); m_gammaLUT = ctx.newDynamicTexture(256, 256, TextureFormat::I16, TextureClampMode::ClampToEdge); setDisplayGamma(1.f); const struct Vert { @@ -879,7 +879,8 @@ class MetalShaderPipeline : public GraphicsDataNode const ObjToken& vtxFmt, NSUInteger targetSamples, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling, bool depthAttachment = true) + bool alphaWrite, bool overwriteAlpha, CullMode culling, + bool depthAttachment = true) : GraphicsDataNode(parent), m_drawPrim(PRIMITIVE_TABLE[int(prim)]), m_vert(std::move(vert)), m_frag(std::move(frag)) @@ -912,15 +913,36 @@ class MetalShaderPipeline : public GraphicsDataNode desc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; desc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne; desc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationReverseSubtract; + if (overwriteAlpha) + { + desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; + desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero; + desc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; + } + else + { + desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; + desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne; + desc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationReverseSubtract; + } } else { desc.colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)]; desc.colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)]; desc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + if (overwriteAlpha) + { + desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; + desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero; + } + else + { + desc.colorAttachments[0].sourceAlphaBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)]; + desc.colorAttachments[0].destinationAlphaBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)]; + } + desc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd; } - desc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne; - desc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorZero; desc.depthAttachmentPixelFormat = depthAttachment ? MTLPixelFormatDepth32Float : MTLPixelFormatInvalid; desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle; NSError* err = nullptr; @@ -1640,7 +1662,8 @@ MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char* const ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling, bool depthAttachment) + bool alphaWrite, CullMode culling, bool overwriteAlpha, + bool depthAttachment) { @autoreleasepool { @@ -1769,7 +1792,7 @@ MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char* return {new MetalShaderPipeline(m_data, factory.m_ctx, std::move(vertShader), std::move(fragShader), vtxFmt, depthAttachment ? factory.m_ctx->m_sampleCount : 1, srcFac, dstFac, prim, depthTest, depthWrite, - colorWrite, alphaWrite, culling, depthAttachment)}; + colorWrite, alphaWrite, overwriteAlpha, culling, depthAttachment)}; } } diff --git a/lib/graphicsdev/Vulkan.cpp b/lib/graphicsdev/Vulkan.cpp index e1d56ad..17bbb90 100644 --- a/lib/graphicsdev/Vulkan.cpp +++ b/lib/graphicsdev/Vulkan.cpp @@ -2164,6 +2164,7 @@ class VulkanShaderPipeline : public GraphicsDataNode bool m_depthWrite; bool m_colorWrite; bool m_alphaWrite; + bool m_overwriteAlpha; CullMode m_culling; mutable VkPipeline m_pipeline = VK_NULL_HANDLE; @@ -2175,12 +2176,12 @@ class VulkanShaderPipeline : public GraphicsDataNode const boo::ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling) + bool alphaWrite, bool overwriteAlpha, CullMode culling) : GraphicsDataNode(parent), m_ctx(ctx), m_pipelineCache(pipelineCache), m_vtxFmt(vtxFmt), m_vert(std::move(vert)), m_frag(std::move(frag)), m_srcFac(srcFac), m_dstFac(dstFac), m_prim(prim), m_depthTest(depthTest), m_depthWrite(depthWrite), m_colorWrite(colorWrite), - m_alphaWrite(alphaWrite), m_culling(culling) + m_alphaWrite(alphaWrite), m_overwriteAlpha(overwriteAlpha), m_culling(culling) {} public: ~VulkanShaderPipeline() @@ -2308,16 +2309,36 @@ public: colorAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; colorAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; colorAttachment.colorBlendOp = VK_BLEND_OP_REVERSE_SUBTRACT; + if (m_overwriteAlpha) + { + colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + colorAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + } + else + { + colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorAttachment.alphaBlendOp = VK_BLEND_OP_REVERSE_SUBTRACT; + } } else { colorAttachment.srcColorBlendFactor = BLEND_FACTOR_TABLE[int(m_srcFac)]; colorAttachment.dstColorBlendFactor = BLEND_FACTOR_TABLE[int(m_dstFac)]; colorAttachment.colorBlendOp = VK_BLEND_OP_ADD; + if (m_overwriteAlpha) + { + colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + } + else + { + colorAttachment.srcAlphaBlendFactor = BLEND_FACTOR_TABLE[int(m_srcFac)]; + colorAttachment.dstAlphaBlendFactor = BLEND_FACTOR_TABLE[int(m_dstFac)]; + } + colorAttachment.alphaBlendOp = VK_BLEND_OP_ADD; } - colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - colorAttachment.alphaBlendOp = VK_BLEND_OP_ADD; colorAttachment.colorWriteMask = (m_colorWrite ? (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | @@ -3561,7 +3582,7 @@ boo::ObjToken VulkanDataFactory::Context::newShaderPipeline std::vector* pipelineBlob, const boo::ObjToken& vtxFmt, BlendFactor srcFac, BlendFactor dstFac, Primitive prim, ZTest depthTest, bool depthWrite, bool colorWrite, - bool alphaWrite, CullMode culling) + bool alphaWrite, CullMode culling, bool overwriteAlpha) { VulkanDataFactoryImpl& factory = static_cast(m_parent); @@ -3688,7 +3709,7 @@ boo::ObjToken VulkanDataFactory::Context::newShaderPipeline VulkanShaderPipeline* retval = new VulkanShaderPipeline(m_data, factory.m_ctx, std::move(vertShader), std::move(fragShader), pipelineCache, vtxFmt, srcFac, dstFac, prim, depthTest, depthWrite, colorWrite, - alphaWrite, culling); + alphaWrite, overwriteAlpha, culling); if (pipelineBlob && pipelineBlob->empty()) {