VK_EXT_blend_operation_advanced minimal implementation This CL adds support for VK_EXT_blend_operation_advanced, with limited features: - VkPipelineColorBlendAdvancedStateCreateInfoEXT::blendOverlap must be VK_BLEND_OVERLAP_UNCORRELATED_EXT - VkPipelineColorBlendAdvancedStateCreateInfoEXT::dstPremultiplied must be VK_TRUE - VkPipelineColorBlendAdvancedStateCreateInfoEXT::srcPremultiplied must be VK_TRUE Tests: dEQP-VK.api.info.vulkan1p2_limits_validation.ext_blend_operation_advanced Tests: dEQP-VK.pipeline.blend_operation_advanced.* Bug: b/203652972 Change-Id: I046452c4399e4895dd98689ce237b50353dcf24a Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/58348 Commit-Queue: Alexis Hétu <sugoi@google.com> Tested-by: Alexis Hétu <sugoi@google.com> Presubmit-Ready: Alexis Hétu <sugoi@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp index 550a815..64148a5 100644 --- a/src/Device/Context.cpp +++ b/src/Device/Context.cpp
@@ -531,6 +531,30 @@ blendConstants.w = colorBlendState->blendConstants[3]; } + const VkBaseInStructure *extensionColorBlendInfo = reinterpret_cast<const VkBaseInStructure *>(colorBlendState->pNext); + while(extensionColorBlendInfo) + { + switch(extensionColorBlendInfo->sType) + { + case VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT: + { + const VkPipelineColorBlendAdvancedStateCreateInfoEXT *colorBlendAdvancedCreateInfo = reinterpret_cast<const VkPipelineColorBlendAdvancedStateCreateInfoEXT *>(extensionColorBlendInfo); + ASSERT(colorBlendAdvancedCreateInfo->blendOverlap == VK_BLEND_OVERLAP_UNCORRELATED_EXT); + ASSERT(colorBlendAdvancedCreateInfo->dstPremultiplied == VK_TRUE); + ASSERT(colorBlendAdvancedCreateInfo->srcPremultiplied == VK_TRUE); + } + break; + case VK_STRUCTURE_TYPE_MAX_ENUM: + // dEQP tests that this value is ignored. + break; + default: + UNSUPPORTED("pCreateInfo->colorBlendState->pNext sType = %s", vk::Stringify(extensionColorBlendInfo->sType).c_str()); + break; + } + + extensionColorBlendInfo = extensionColorBlendInfo->pNext; + } + ASSERT(colorBlendState->attachmentCount <= sw::MAX_COLOR_BUFFERS); for(auto i = 0u; i < colorBlendState->attachmentCount; i++) { @@ -725,8 +749,22 @@ case VK_BLEND_OP_REVERSE_SUBTRACT: return blendState[index].sourceBlendFactor; case VK_BLEND_OP_MIN: - return VK_BLEND_FACTOR_ONE; case VK_BLEND_OP_MAX: + case VK_BLEND_OP_MULTIPLY_EXT: + case VK_BLEND_OP_SCREEN_EXT: + case VK_BLEND_OP_OVERLAY_EXT: + case VK_BLEND_OP_DARKEN_EXT: + case VK_BLEND_OP_LIGHTEN_EXT: + case VK_BLEND_OP_COLORDODGE_EXT: + case VK_BLEND_OP_COLORBURN_EXT: + case VK_BLEND_OP_HARDLIGHT_EXT: + case VK_BLEND_OP_SOFTLIGHT_EXT: + case VK_BLEND_OP_DIFFERENCE_EXT: + case VK_BLEND_OP_EXCLUSION_EXT: + case VK_BLEND_OP_HSL_HUE_EXT: + case VK_BLEND_OP_HSL_SATURATION_EXT: + case VK_BLEND_OP_HSL_COLOR_EXT: + case VK_BLEND_OP_HSL_LUMINOSITY_EXT: return VK_BLEND_FACTOR_ONE; default: ASSERT(false); @@ -748,8 +786,22 @@ case VK_BLEND_OP_REVERSE_SUBTRACT: return blendState[index].destBlendFactor; case VK_BLEND_OP_MIN: - return VK_BLEND_FACTOR_ONE; case VK_BLEND_OP_MAX: + case VK_BLEND_OP_MULTIPLY_EXT: + case VK_BLEND_OP_SCREEN_EXT: + case VK_BLEND_OP_OVERLAY_EXT: + case VK_BLEND_OP_DARKEN_EXT: + case VK_BLEND_OP_LIGHTEN_EXT: + case VK_BLEND_OP_COLORDODGE_EXT: + case VK_BLEND_OP_COLORBURN_EXT: + case VK_BLEND_OP_HARDLIGHT_EXT: + case VK_BLEND_OP_SOFTLIGHT_EXT: + case VK_BLEND_OP_DIFFERENCE_EXT: + case VK_BLEND_OP_EXCLUSION_EXT: + case VK_BLEND_OP_HSL_HUE_EXT: + case VK_BLEND_OP_HSL_SATURATION_EXT: + case VK_BLEND_OP_HSL_COLOR_EXT: + case VK_BLEND_OP_HSL_LUMINOSITY_EXT: return VK_BLEND_FACTOR_ONE; default: ASSERT(false); @@ -862,9 +914,23 @@ } } case VK_BLEND_OP_MIN: - return VK_BLEND_OP_MIN; case VK_BLEND_OP_MAX: - return VK_BLEND_OP_MAX; + case VK_BLEND_OP_MULTIPLY_EXT: + case VK_BLEND_OP_SCREEN_EXT: + case VK_BLEND_OP_OVERLAY_EXT: + case VK_BLEND_OP_DARKEN_EXT: + case VK_BLEND_OP_LIGHTEN_EXT: + case VK_BLEND_OP_COLORDODGE_EXT: + case VK_BLEND_OP_COLORBURN_EXT: + case VK_BLEND_OP_HARDLIGHT_EXT: + case VK_BLEND_OP_SOFTLIGHT_EXT: + case VK_BLEND_OP_DIFFERENCE_EXT: + case VK_BLEND_OP_EXCLUSION_EXT: + case VK_BLEND_OP_HSL_HUE_EXT: + case VK_BLEND_OP_HSL_SATURATION_EXT: + case VK_BLEND_OP_HSL_COLOR_EXT: + case VK_BLEND_OP_HSL_LUMINOSITY_EXT: + return blendState[index].blendOperation; default: ASSERT(false); } @@ -883,8 +949,22 @@ case VK_BLEND_OP_REVERSE_SUBTRACT: return blendState[index].sourceBlendFactorAlpha; case VK_BLEND_OP_MIN: - return VK_BLEND_FACTOR_ONE; case VK_BLEND_OP_MAX: + case VK_BLEND_OP_MULTIPLY_EXT: + case VK_BLEND_OP_SCREEN_EXT: + case VK_BLEND_OP_OVERLAY_EXT: + case VK_BLEND_OP_DARKEN_EXT: + case VK_BLEND_OP_LIGHTEN_EXT: + case VK_BLEND_OP_COLORDODGE_EXT: + case VK_BLEND_OP_COLORBURN_EXT: + case VK_BLEND_OP_HARDLIGHT_EXT: + case VK_BLEND_OP_SOFTLIGHT_EXT: + case VK_BLEND_OP_DIFFERENCE_EXT: + case VK_BLEND_OP_EXCLUSION_EXT: + case VK_BLEND_OP_HSL_HUE_EXT: + case VK_BLEND_OP_HSL_SATURATION_EXT: + case VK_BLEND_OP_HSL_COLOR_EXT: + case VK_BLEND_OP_HSL_LUMINOSITY_EXT: return VK_BLEND_FACTOR_ONE; default: ASSERT(false); @@ -904,8 +984,22 @@ case VK_BLEND_OP_REVERSE_SUBTRACT: return blendState[index].destBlendFactorAlpha; case VK_BLEND_OP_MIN: - return VK_BLEND_FACTOR_ONE; case VK_BLEND_OP_MAX: + case VK_BLEND_OP_MULTIPLY_EXT: + case VK_BLEND_OP_SCREEN_EXT: + case VK_BLEND_OP_OVERLAY_EXT: + case VK_BLEND_OP_DARKEN_EXT: + case VK_BLEND_OP_LIGHTEN_EXT: + case VK_BLEND_OP_COLORDODGE_EXT: + case VK_BLEND_OP_COLORBURN_EXT: + case VK_BLEND_OP_HARDLIGHT_EXT: + case VK_BLEND_OP_SOFTLIGHT_EXT: + case VK_BLEND_OP_DIFFERENCE_EXT: + case VK_BLEND_OP_EXCLUSION_EXT: + case VK_BLEND_OP_HSL_HUE_EXT: + case VK_BLEND_OP_HSL_SATURATION_EXT: + case VK_BLEND_OP_HSL_COLOR_EXT: + case VK_BLEND_OP_HSL_LUMINOSITY_EXT: return VK_BLEND_FACTOR_ONE; default: ASSERT(false); @@ -1019,6 +1113,24 @@ return VK_BLEND_OP_MIN; case VK_BLEND_OP_MAX: return VK_BLEND_OP_MAX; + case VK_BLEND_OP_MULTIPLY_EXT: + case VK_BLEND_OP_SCREEN_EXT: + case VK_BLEND_OP_OVERLAY_EXT: + case VK_BLEND_OP_DARKEN_EXT: + case VK_BLEND_OP_LIGHTEN_EXT: + case VK_BLEND_OP_COLORDODGE_EXT: + case VK_BLEND_OP_COLORBURN_EXT: + case VK_BLEND_OP_HARDLIGHT_EXT: + case VK_BLEND_OP_SOFTLIGHT_EXT: + case VK_BLEND_OP_DIFFERENCE_EXT: + case VK_BLEND_OP_EXCLUSION_EXT: + case VK_BLEND_OP_HSL_HUE_EXT: + case VK_BLEND_OP_HSL_SATURATION_EXT: + case VK_BLEND_OP_HSL_COLOR_EXT: + case VK_BLEND_OP_HSL_LUMINOSITY_EXT: + // All of the currently supported advanced blend modes compute the alpha the same way + // Use VK_BLEND_OP_MULTIPLY_EXT as a placeholder + return VK_BLEND_OP_MULTIPLY_EXT; default: ASSERT(false); }
diff --git a/src/Pipeline/PixelRoutine.cpp b/src/Pipeline/PixelRoutine.cpp index 8053391..ab1187c 100644 --- a/src/Pipeline/PixelRoutine.cpp +++ b/src/Pipeline/PixelRoutine.cpp
@@ -1948,6 +1948,243 @@ } } +Float4 PixelRoutine::blendOpOverlay(Float4 &src, Float4 &dst) +{ + Int4 largeDst = CmpGT(dst, Float4(0.5f)); + return As<Float4>( + (~largeDst & + As<Int4>(Float4(2.0f) * src * dst)) | + (largeDst & + As<Int4>(Float4(1.0f) - (Float4(2.0f) * (Float4(1.0f) - src) * (Float4(1.0f) - dst))))); +} + +Float4 PixelRoutine::blendOpColorDodge(Float4 &src, Float4 &dst) +{ + Int4 srcBelowOne = CmpLT(src, Float4(1.0f)); + Int4 positiveDst = CmpGT(dst, Float4(0.0f)); + return As<Float4>(positiveDst & ((~srcBelowOne & + As<Int4>(Float4(1.0f))) | + (srcBelowOne & + As<Int4>(Min(Float4(1.0f), (dst / (Float4(1.0f) - src))))))); +} + +Float4 PixelRoutine::blendOpColorBurn(Float4 &src, Float4 &dst) +{ + Int4 dstBelowOne = CmpLT(dst, Float4(1.0f)); + Int4 positiveSrc = CmpGT(src, Float4(0.0f)); + return As<Float4>( + (~dstBelowOne & + As<Int4>(Float4(1.0f))) | + (dstBelowOne & positiveSrc & + As<Int4>(Float4(1.0f) - Min(Float4(1.0f), (Float4(1.0f) - dst) / src)))); +} + +Float4 PixelRoutine::blendOpHardlight(Float4 &src, Float4 &dst) +{ + Int4 largeSrc = CmpGT(src, Float4(0.5f)); + return As<Float4>( + (~largeSrc & + As<Int4>(Float4(2.0f) * src * dst)) | + (largeSrc & + As<Int4>(Float4(1.0f) - (Float4(2.0f) * (Float4(1.0f) - src) * (Float4(1.0f) - dst))))); +} + +Float4 PixelRoutine::blendOpSoftlight(Float4 &src, Float4 &dst) +{ + Int4 largeSrc = CmpGT(src, Float4(0.5f)); + Int4 largeDst = CmpGT(dst, Float4(0.25f)); + + return As<Float4>( + (~largeSrc & + As<Int4>(dst - ((Float4(1.0f) - (Float4(2.0f) * src)) * dst * (Float4(1.0f) - dst)))) | + (largeSrc & ((~largeDst & + As<Int4>(dst + (((Float4(2.0f) * src) - Float4(1.0f)) * dst * ((((Float4(16.0f) * dst) - Float4(12.0f)) * dst) + Float4(3.0f))))) | + (largeDst & + As<Int4>(dst + (((Float4(2.0f) * src) - Float4(1.0f)) * (Sqrt(dst) - dst))))))); +} + +Float4 PixelRoutine::maxRGB(Vector4f &c) +{ + return Max(Max(c.x, c.y), c.z); +} + +Float4 PixelRoutine::minRGB(Vector4f &c) +{ + return Min(Min(c.x, c.y), c.z); +} + +void PixelRoutine::setLumSat(Vector4f &cbase, Vector4f &csat, Vector4f &clum, Float4 &x, Float4 &y, Float4 &z) +{ + Float4 minbase = minRGB(cbase); + Float4 sbase = maxRGB(cbase) - minbase; + Float4 ssat = maxRGB(csat) - minRGB(csat); + Int4 isNonZero = CmpGT(sbase, Float4(0.0f)); + Vector4f color; + color.x = As<Float4>(isNonZero & As<Int4>((cbase.x - minbase) * ssat / sbase)); + color.y = As<Float4>(isNonZero & As<Int4>((cbase.y - minbase) * ssat / sbase)); + color.z = As<Float4>(isNonZero & As<Int4>((cbase.z - minbase) * ssat / sbase)); + setLum(color, clum, x, y, z); +} + +Float4 PixelRoutine::lumRGB(Vector4f &c) +{ + return c.x * Float4(0.3f) + c.y * Float4(0.59f) + c.z * Float4(0.11f); +} + +Float4 PixelRoutine::computeLum(Float4 &color, Float4 &lum, Float4 &mincol, Float4 &maxcol, Int4 &negative, Int4 &aboveOne) +{ + return As<Float4>( + (negative & + As<Int4>(lum + ((color - lum) * lum) / (lum - mincol))) | + (~negative & + ((aboveOne & + As<Int4>(lum + ((color - lum) * (Float4(1.0f) - lum)) / (Float4(maxcol) - lum))) | + (~aboveOne & + As<Int4>(color))))); +} + +void PixelRoutine::setLum(Vector4f &cbase, Vector4f &clum, Float4 &x, Float4 &y, Float4 &z) +{ + Float4 lbase = lumRGB(cbase); + Float4 llum = lumRGB(clum); + Float4 ldiff = llum - lbase; + + Vector4f color; + color.x = cbase.x + ldiff; + color.y = cbase.y + ldiff; + color.z = cbase.z + ldiff; + + Float4 lum = lumRGB(color); + Float4 mincol = minRGB(color); + Float4 maxcol = maxRGB(color); + + Int4 negative = CmpLT(mincol, Float4(0.0f)); + Int4 aboveOne = CmpGT(maxcol, Float4(1.0f)); + + x = computeLum(color.x, lum, mincol, maxcol, negative, aboveOne); + y = computeLum(color.y, lum, mincol, maxcol, negative, aboveOne); + z = computeLum(color.z, lum, mincol, maxcol, negative, aboveOne); +} + +void PixelRoutine::premultiply(Vector4f &c) +{ + Int4 nonZeroAlpha = CmpNEQ(c.w, Float4(0.0f)); + c.x = As<Float4>(nonZeroAlpha & As<Int4>(c.x / c.w)); + c.y = As<Float4>(nonZeroAlpha & As<Int4>(c.y / c.w)); + c.z = As<Float4>(nonZeroAlpha & As<Int4>(c.z / c.w)); +} + +Vector4f PixelRoutine::computeAdvancedBlendMode(int index, const Vector4f &src, const Vector4f &dst, const Vector4f &srcFactor, const Vector4f &dstFactor) +{ + Vector4f srcColor = src; + srcColor.x *= srcFactor.x; + srcColor.y *= srcFactor.y; + srcColor.z *= srcFactor.z; + srcColor.w *= srcFactor.w; + + Vector4f dstColor = dst; + dstColor.x *= dstFactor.x; + dstColor.y *= dstFactor.y; + dstColor.z *= dstFactor.z; + dstColor.w *= dstFactor.w; + + premultiply(srcColor); + premultiply(dstColor); + + Vector4f blendedColor; + + switch(state.blendState[index].blendOperation) + { + case VK_BLEND_OP_MULTIPLY_EXT: + blendedColor.x = (srcColor.x * dstColor.x); + blendedColor.y = (srcColor.y * dstColor.y); + blendedColor.z = (srcColor.z * dstColor.z); + break; + case VK_BLEND_OP_SCREEN_EXT: + blendedColor.x = srcColor.x + dstColor.x - (srcColor.x * dstColor.x); + blendedColor.y = srcColor.y + dstColor.y - (srcColor.y * dstColor.y); + blendedColor.z = srcColor.z + dstColor.z - (srcColor.z * dstColor.z); + break; + case VK_BLEND_OP_OVERLAY_EXT: + blendedColor.x = blendOpOverlay(srcColor.x, dstColor.x); + blendedColor.y = blendOpOverlay(srcColor.y, dstColor.y); + blendedColor.z = blendOpOverlay(srcColor.z, dstColor.z); + break; + case VK_BLEND_OP_DARKEN_EXT: + blendedColor.x = Min(srcColor.x, dstColor.x); + blendedColor.y = Min(srcColor.y, dstColor.y); + blendedColor.z = Min(srcColor.z, dstColor.z); + break; + case VK_BLEND_OP_LIGHTEN_EXT: + blendedColor.x = Max(srcColor.x, dstColor.x); + blendedColor.y = Max(srcColor.y, dstColor.y); + blendedColor.z = Max(srcColor.z, dstColor.z); + break; + case VK_BLEND_OP_COLORDODGE_EXT: + blendedColor.x = blendOpColorDodge(srcColor.x, dstColor.x); + blendedColor.y = blendOpColorDodge(srcColor.y, dstColor.y); + blendedColor.z = blendOpColorDodge(srcColor.z, dstColor.z); + break; + case VK_BLEND_OP_COLORBURN_EXT: + blendedColor.x = blendOpColorBurn(srcColor.x, dstColor.x); + blendedColor.y = blendOpColorBurn(srcColor.y, dstColor.y); + blendedColor.z = blendOpColorBurn(srcColor.z, dstColor.z); + break; + case VK_BLEND_OP_HARDLIGHT_EXT: + blendedColor.x = blendOpHardlight(srcColor.x, dstColor.x); + blendedColor.y = blendOpHardlight(srcColor.y, dstColor.y); + blendedColor.z = blendOpHardlight(srcColor.z, dstColor.z); + break; + case VK_BLEND_OP_SOFTLIGHT_EXT: + blendedColor.x = blendOpSoftlight(srcColor.x, dstColor.x); + blendedColor.y = blendOpSoftlight(srcColor.y, dstColor.y); + blendedColor.z = blendOpSoftlight(srcColor.z, dstColor.z); + break; + case VK_BLEND_OP_DIFFERENCE_EXT: + blendedColor.x = Abs(srcColor.x - dstColor.x); + blendedColor.y = Abs(srcColor.y - dstColor.y); + blendedColor.z = Abs(srcColor.z - dstColor.z); + break; + case VK_BLEND_OP_EXCLUSION_EXT: + blendedColor.x = srcColor.x + dstColor.x - (srcColor.x * dstColor.x * Float4(2.0f)); + blendedColor.y = srcColor.y + dstColor.y - (srcColor.y * dstColor.y * Float4(2.0f)); + blendedColor.z = srcColor.z + dstColor.z - (srcColor.z * dstColor.z * Float4(2.0f)); + break; + case VK_BLEND_OP_HSL_HUE_EXT: + setLumSat(srcColor, dstColor, dstColor, blendedColor.x, blendedColor.y, blendedColor.z); + break; + case VK_BLEND_OP_HSL_SATURATION_EXT: + setLumSat(dstColor, srcColor, dstColor, blendedColor.x, blendedColor.y, blendedColor.z); + break; + case VK_BLEND_OP_HSL_COLOR_EXT: + setLum(srcColor, dstColor, blendedColor.x, blendedColor.y, blendedColor.z); + break; + case VK_BLEND_OP_HSL_LUMINOSITY_EXT: + setLum(dstColor, srcColor, blendedColor.x, blendedColor.y, blendedColor.z); + break; + default: + UNSUPPORTED("Unsupported advanced VkBlendOp: %d", int(state.blendState[index].blendOperation)); + break; + } + + Float4 p = srcColor.w * dstColor.w; + blendedColor.x *= p; + blendedColor.y *= p; + blendedColor.z *= p; + + p = srcColor.w * (Float4(1.0f) - dstColor.w); + blendedColor.x += srcColor.x * p; + blendedColor.y += srcColor.y * p; + blendedColor.z += srcColor.z * p; + + p = dstColor.w * (Float4(1.0f) - srcColor.w); + blendedColor.x += dstColor.x * p; + blendedColor.y += dstColor.y * p; + blendedColor.z += dstColor.z * p; + + return blendedColor; +} + bool PixelRoutine::blendFactorCanExceedFormatRange(VkBlendFactor blendFactor, vk::Format format) { switch(blendFactor) @@ -2162,6 +2399,8 @@ blendFactorRGB(sourceFactor, sourceColor, destColor, state.blendState[index].sourceBlendFactor, format); blendFactorRGB(destFactor, sourceColor, destColor, state.blendState[index].destBlendFactor, format); + blendFactorAlpha(sourceFactor.w, sourceColor.w, destColor.w, state.blendState[index].sourceBlendFactorAlpha, format); + blendFactorAlpha(destFactor.w, sourceColor.w, destColor.w, state.blendState[index].destBlendFactorAlpha, format); Vector4f blendedColor; @@ -2207,13 +2446,27 @@ blendedColor.y = Float4(0.0f); blendedColor.z = Float4(0.0f); break; + case VK_BLEND_OP_MULTIPLY_EXT: + case VK_BLEND_OP_SCREEN_EXT: + case VK_BLEND_OP_OVERLAY_EXT: + case VK_BLEND_OP_DARKEN_EXT: + case VK_BLEND_OP_LIGHTEN_EXT: + case VK_BLEND_OP_COLORDODGE_EXT: + case VK_BLEND_OP_COLORBURN_EXT: + case VK_BLEND_OP_HARDLIGHT_EXT: + case VK_BLEND_OP_SOFTLIGHT_EXT: + case VK_BLEND_OP_DIFFERENCE_EXT: + case VK_BLEND_OP_EXCLUSION_EXT: + case VK_BLEND_OP_HSL_HUE_EXT: + case VK_BLEND_OP_HSL_SATURATION_EXT: + case VK_BLEND_OP_HSL_COLOR_EXT: + case VK_BLEND_OP_HSL_LUMINOSITY_EXT: + blendedColor = computeAdvancedBlendMode(index, sourceColor, destColor, sourceFactor, destFactor); + break; default: UNSUPPORTED("VkBlendOp: %d", int(state.blendState[index].blendOperation)); } - blendFactorAlpha(sourceFactor.w, sourceColor.w, destColor.w, state.blendState[index].sourceBlendFactorAlpha, format); - blendFactorAlpha(destFactor.w, sourceColor.w, destColor.w, state.blendState[index].destBlendFactorAlpha, format); - switch(state.blendState[index].blendOperationAlpha) { case VK_BLEND_OP_ADD: @@ -2240,6 +2493,11 @@ case VK_BLEND_OP_ZERO_EXT: blendedColor.w = Float4(0.0f); break; + case VK_BLEND_OP_MULTIPLY_EXT: + // All of the currently supported advanced blend modes compute the alpha the same way + // Use VK_BLEND_OP_MULTIPLY_EXT as a placeholder + blendedColor.w = sourceColor.w + destColor.w - (sourceColor.w * destColor.w); + break; default: UNSUPPORTED("VkBlendOp: %d", int(state.blendState[index].blendOperationAlpha)); }
diff --git a/src/Pipeline/PixelRoutine.hpp b/src/Pipeline/PixelRoutine.hpp index 3f410e7..ba5f28d 100644 --- a/src/Pipeline/PixelRoutine.hpp +++ b/src/Pipeline/PixelRoutine.hpp
@@ -77,6 +77,19 @@ void blendFactorRGB(Vector4f &blendFactorRGB, const Vector4f &sourceColor, const Vector4f &destColor, VkBlendFactor colorBlendFactor, vk::Format format); void blendFactorAlpha(Float4 &blendFactorAlpha, const Float4 &sourceAlpha, const Float4 &destAlpha, VkBlendFactor alphaBlendFactor, vk::Format format); bool blendFactorCanExceedFormatRange(VkBlendFactor blendFactor, vk::Format format); + Vector4f computeAdvancedBlendMode(int index, const Vector4f &src, const Vector4f &dst, const Vector4f &srcFactor, const Vector4f &dstFactor); + Float4 blendOpOverlay(Float4 &src, Float4 &dst); + Float4 blendOpColorDodge(Float4 &src, Float4 &dst); + Float4 blendOpColorBurn(Float4 &src, Float4 &dst); + Float4 blendOpHardlight(Float4 &src, Float4 &dst); + Float4 blendOpSoftlight(Float4 &src, Float4 &dst); + void setLumSat(Vector4f &cbase, Vector4f &csat, Vector4f &clum, Float4 &x, Float4 &y, Float4 &z); + void setLum(Vector4f &cbase, Vector4f &clum, Float4 &x, Float4 &y, Float4 &z); + Float4 computeLum(Float4 &color, Float4 &lum, Float4 &mincol, Float4 &maxcol, Int4 &negative, Int4 &aboveOne); + Float4 maxRGB(Vector4f &c); + Float4 minRGB(Vector4f &c); + Float4 lumRGB(Vector4f &c); + void premultiply(Vector4f &c); void writeStencil(Pointer<Byte> &sBuffer, const Int &x, const Int sMask[4], const Int zMask[4], const Int cMask[4], const SampleSet &samples); void writeDepth(Pointer<Byte> &zBuffer, const Int &x, const Int zMask[4], const SampleSet &samples); void occlusionSampleCount(const Int zMask[4], const Int sMask[4], const SampleSet &samples);
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp index be9e649..fe8f840 100644 --- a/src/Vulkan/VkPhysicalDevice.cpp +++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -332,12 +332,17 @@ features->depthClipEnable = VK_TRUE; } -static void getPhysicalDevicCustomBorderColorFeaturesExt(VkPhysicalDeviceCustomBorderColorFeaturesEXT *features) +static void getPhysicalDeviceCustomBorderColorFeaturesExt(VkPhysicalDeviceCustomBorderColorFeaturesEXT *features) { features->customBorderColors = VK_TRUE; features->customBorderColorWithoutFormat = VK_TRUE; } +static void getPhysicalDeviceBlendOperationAdvancedFeaturesExt(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *features) +{ + features->advancedBlendCoherentOperations = VK_FALSE; +} + static void getPhysicalDevice4444FormatsFeaturesExt(VkPhysicalDevice4444FormatsFeaturesEXT *features) { features->formatA4R4G4B4 = VK_TRUE; @@ -437,7 +442,10 @@ getPhysicalDeviceDepthClipEnableFeaturesExt(reinterpret_cast<VkPhysicalDeviceDepthClipEnableFeaturesEXT *>(curExtension)); break; case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: - getPhysicalDevicCustomBorderColorFeaturesExt(reinterpret_cast<VkPhysicalDeviceCustomBorderColorFeaturesEXT *>(curExtension)); + getPhysicalDeviceCustomBorderColorFeaturesExt(reinterpret_cast<VkPhysicalDeviceCustomBorderColorFeaturesEXT *>(curExtension)); + break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT: + getPhysicalDeviceBlendOperationAdvancedFeaturesExt(reinterpret_cast<VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *>(curExtension)); break; case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: getPhysicalDevice4444FormatsFeaturesExt(reinterpret_cast<struct VkPhysicalDevice4444FormatsFeaturesEXT *>(curExtension)); @@ -1034,6 +1042,18 @@ properties->maxCustomBorderColorSamplers = MAX_SAMPLER_ALLOCATION_COUNT; } +void PhysicalDevice::getProperties(VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *properties) const +{ + // Note: advancedBlendMaxColorAttachments could already support sw::MAX_COLOR_BUFFERS as is, + // but using a value of 1 is enough for ANGLE to implement GL_KHR_blend_equation_advanced + properties->advancedBlendMaxColorAttachments = 1; + properties->advancedBlendIndependentBlend = VK_FALSE; + properties->advancedBlendNonPremultipliedSrcColor = VK_FALSE; + properties->advancedBlendNonPremultipliedDstColor = VK_FALSE; + properties->advancedBlendCorrelatedOverlap = VK_FALSE; + properties->advancedBlendAllOperations = VK_FALSE; +} + template<typename T> static void getSamplerFilterMinmaxProperties(T *properties) { @@ -1121,6 +1141,7 @@ InstantiateHasExtendedFeatures(VkPhysicalDeviceVulkan11Features); InstantiateHasExtendedFeatures(VkPhysicalDeviceVulkan12Features); InstantiateHasExtendedFeatures(VkPhysicalDeviceDepthClipEnableFeaturesEXT); +InstantiateHasExtendedFeatures(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT); #undef InstantiateHasExtendedFeatures void PhysicalDevice::GetFormatProperties(Format format, VkFormatProperties *pFormatProperties)
diff --git a/src/Vulkan/VkPhysicalDevice.hpp b/src/Vulkan/VkPhysicalDevice.hpp index 068011a..080d1af 100644 --- a/src/Vulkan/VkPhysicalDevice.hpp +++ b/src/Vulkan/VkPhysicalDevice.hpp
@@ -68,6 +68,7 @@ void getProperties(VkPhysicalDeviceDescriptorIndexingProperties *properties) const; void getProperties(VkPhysicalDeviceDepthStencilResolveProperties *properties) const; void getProperties(VkPhysicalDeviceCustomBorderColorPropertiesEXT *properties) const; + void getProperties(VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *properties) const; void getProperties(VkPhysicalDeviceVulkan11Properties *properties) const; static void GetFormatProperties(Format format, VkFormatProperties *pFormatProperties);
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp index 2017350..5faaf75 100644 --- a/src/Vulkan/libVulkan.cpp +++ b/src/Vulkan/libVulkan.cpp
@@ -371,6 +371,8 @@ { { VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME, VK_EXT_IMAGE_ROBUSTNESS_SPEC_VERSION } }, // Useful for D3D emulation { { VK_EXT_4444_FORMATS_EXTENSION_NAME, VK_EXT_4444_FORMATS_SPEC_VERSION } }, + // Used by ANGLE to support GL_KHR_blend_equation_advanced + { { VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION } }, #ifndef __ANDROID__ // We fully support the KHR_swapchain v70 additions, so just track the spec version. { { VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_SPEC_VERSION } }, @@ -917,6 +919,16 @@ } } break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT: + { + const auto *blendOpFeatures = reinterpret_cast<const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *>(extensionCreateInfo); + bool hasFeatures = vk::Cast(physicalDevice)->hasExtendedFeatures(blendOpFeatures); + if(!hasFeatures) + { + return VK_ERROR_FEATURE_NOT_PRESENT; + } + } + break; // These structs are supported, but no behavior changes based on their feature bools case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES: case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES: @@ -3253,6 +3265,12 @@ vk::Cast(physicalDevice)->getProperties(properties); } break; + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT: + { + auto properties = reinterpret_cast<VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *>(extensionProperties); + vk::Cast(physicalDevice)->getProperties(properties); + } + break; case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR: break; default: