diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h index 8f0c801b0..0de1a7293 100644 --- a/include/GLSLANG/ShaderLang.h +++ b/include/GLSLANG/ShaderLang.h @@ -26,7 +26,7 @@ // Version number for shader translation API. // It is incremented every time the API changes. -#define ANGLE_SH_VERSION 300 +#define ANGLE_SH_VERSION 301 enum ShShaderSpec { @@ -805,6 +805,7 @@ unsigned int GetImage2DRegisterIndex(const ShHandle handle); // handle: Specifies the compiler const std::set *GetUsedImage2DFunctionNames(const ShHandle handle); +bool HasDiscardInFragmentShader(const ShHandle handle); bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle); bool HasValidGeometryShaderOutputPrimitiveType(const ShHandle handle); bool HasValidGeometryShaderMaxVertices(const ShHandle handle); diff --git a/include/platform/FeaturesVk_autogen.h b/include/platform/FeaturesVk_autogen.h index a5cfd82f6..1706d0ce1 100644 --- a/include/platform/FeaturesVk_autogen.h +++ b/include/platform/FeaturesVk_autogen.h @@ -670,6 +670,12 @@ struct FeaturesVk : FeatureSetBase "VkDevice supports VK_ANDROID_render_to_external_format and VK_EXT_ycbcr_attachment", &members, }; + + FeatureInfo useNonZeroStencilWriteMaskStaticState = { + "useNonZeroStencilWriteMaskStaticState", FeatureCategory::VulkanWorkarounds, + "Work around a driver bug where 0 in stencil write mask static state would make the" + "corresponding dynamic state malfunction in the presence of discard or alpha to coverage", + &members, "http://anglebug.com/7556"}; }; inline FeaturesVk::FeaturesVk() = default; diff --git a/include/platform/vk_features.json b/include/platform/vk_features.json index 2bb924f83..5889eecf2 100644 --- a/include/platform/vk_features.json +++ b/include/platform/vk_features.json @@ -900,6 +900,15 @@ "description": [ "VkDevice supports VK_ANDROID_render_to_external_format and VK_EXT_ycbcr_attachment" ] + }, + { + "name": "use_non_zero_stencil_write_mask_static_state", + "category": "Workarounds", + "description": [ + "Work around a driver bug where 0 in stencil write mask static state would make the", + "corresponding dynamic state malfunction in the presence of discard or alpha to coverage" + ], + "issue": "http://anglebug.com/7556" } ] } diff --git a/scripts/code_generation_hashes/ANGLE_features.json b/scripts/code_generation_hashes/ANGLE_features.json index 3adf4a3c5..fbc3e5e6d 100644 --- a/scripts/code_generation_hashes/ANGLE_features.json +++ b/scripts/code_generation_hashes/ANGLE_features.json @@ -6,7 +6,7 @@ "include/platform/FeaturesMtl_autogen.h": "6b6d49c35bc9246361f8dac0a5445a02", "include/platform/FeaturesVk_autogen.h": - "ab5ace9dfe770836cc0532cb44a0d689", + "858c952c9988cfdb448ebf5ac24d3433", "include/platform/FrontendFeatures_autogen.h": "1781e4fa6efb552bca2ce5a5164eb374", "include/platform/d3d_features.json": @@ -20,9 +20,9 @@ "include/platform/mtl_features.json": "1fabfe4d5c2eb3683a5b567ab60ad83c", "include/platform/vk_features.json": - "712395bb25e2492ea13fba1c8131f481", + "584d2949c0cc9e59f479748e583af9ef", "util/angle_features_autogen.cpp": - "adf8f4a7e32d3229aa42bb7a96842d5b", + "e5742cc5b6a78cfed2345067f2a247b2", "util/angle_features_autogen.h": - "92d40c02e5b2741b33bcc88aa759cfde" + "9bbae74bf2e9816ebe2f9002dd8f2fd2" } \ No newline at end of file diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp index 12644d799..9e461c7ab 100644 --- a/src/compiler/translator/Compiler.cpp +++ b/src/compiler/translator/Compiler.cpp @@ -553,6 +553,8 @@ void TCompiler::setASTMetadata(const TParseContext &parseContext) mEarlyFragmentTestsSpecified = parseContext.isEarlyFragmentTestsSpecified(); + mHasDiscard = parseContext.hasDiscard(); + mEnablesPerSampleShading = parseContext.isSampleQualifierSpecified(); mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared(); diff --git a/src/compiler/translator/Compiler.h b/src/compiler/translator/Compiler.h index cbc52d80e..c232bb347 100644 --- a/src/compiler/translator/Compiler.h +++ b/src/compiler/translator/Compiler.h @@ -112,6 +112,7 @@ class TCompiler : public TShHandleBase TInfoSink &getInfoSink() { return mInfoSink; } bool isEarlyFragmentTestsSpecified() const { return mEarlyFragmentTestsSpecified; } + bool hasDiscard() const { return mHasDiscard; } bool enablesPerSampleShading() const { return mEnablesPerSampleShading; } SpecConstUsageBits getSpecConstUsageBits() const { return mSpecConstUsageBits; } @@ -317,9 +318,12 @@ class TCompiler : public TShHandleBase TDiagnostics mDiagnostics; const char *mSourcePath; // Path of source file or NULL - // fragment shader early fragment tests + // Fragment shader early fragment tests bool mEarlyFragmentTestsSpecified; + // Fragment shader has the discard instruction + bool mHasDiscard; + // Whether per-sample shading is enabled by the shader. In OpenGL, this keyword should // implicitly trigger per-sample shading without the API enabling it. bool mEnablesPerSampleShading; diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp index 36f768fb3..0a047cce0 100644 --- a/src/compiler/translator/ParseContext.cpp +++ b/src/compiler/translator/ParseContext.cpp @@ -210,6 +210,7 @@ TParseContext::TParseContext(TSymbolTable &symt, mChecksPrecisionErrors(checksPrecErrors), mFragmentPrecisionHighOnESSL1(false), mEarlyFragmentTestsSpecified(false), + mHasDiscard(false), mSampleQualifierSpecified(false), mDefaultUniformMatrixPacking(EmpColumnMajor), mDefaultUniformBlockStorage(sh::IsWebGLBasedSpec(spec) ? EbsStd140 : EbsShared), @@ -6810,6 +6811,7 @@ TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) { errorIfPLSDeclared(loc, PLSIllegalOperations::Discard); } + mHasDiscard = true; break; default: UNREACHABLE(); diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h index b98db5f3c..666f5e385 100644 --- a/src/compiler/translator/ParseContext.h +++ b/src/compiler/translator/ParseContext.h @@ -76,6 +76,7 @@ class TParseContext : angle::NonCopyable } bool isEarlyFragmentTestsSpecified() const { return mEarlyFragmentTestsSpecified; } + bool hasDiscard() const { return mHasDiscard; } bool isSampleQualifierSpecified() const { return mSampleQualifierSpecified; } void setLoopNestingLevel(int loopNestintLevel) { mLoopNestingLevel = loopNestintLevel; } @@ -731,8 +732,9 @@ class TParseContext : angle::NonCopyable // without precision, explicit or implicit. bool mFragmentPrecisionHighOnESSL1; // true if highp precision is supported when compiling // ESSL1. - bool mEarlyFragmentTestsSpecified; // true if layout(early_fragment_tests) in; is specified. - bool mSampleQualifierSpecified; // true if the |sample| qualifier is used + bool mEarlyFragmentTestsSpecified; // true if |layout(early_fragment_tests) in| is specified. + bool mHasDiscard; // true if |discard| is encountered in the shader. + bool mSampleQualifierSpecified; // true if the |sample| qualifier is used. TLayoutMatrixPacking mDefaultUniformMatrixPacking; TLayoutBlockStorage mDefaultUniformBlockStorage; TLayoutMatrixPacking mDefaultBufferMatrixPacking; diff --git a/src/compiler/translator/ShaderLang.cpp b/src/compiler/translator/ShaderLang.cpp index 3e3fa9beb..e54751ae5 100644 --- a/src/compiler/translator/ShaderLang.cpp +++ b/src/compiler/translator/ShaderLang.cpp @@ -736,6 +736,17 @@ const std::set *GetUsedImage2DFunctionNames(const ShHandle handle) #endif // ANGLE_ENABLE_HLSL } +bool HasDiscardInFragmentShader(const ShHandle handle) +{ + ASSERT(handle); + + TShHandleBase *base = static_cast(handle); + TCompiler *compiler = base->getAsCompiler(); + ASSERT(compiler); + + return compiler->getShaderType() == GL_FRAGMENT_SHADER && compiler->hasDiscard(); +} + bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle) { ASSERT(handle); diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp index d0b3f7fdb..36c023596 100644 --- a/src/libANGLE/Program.cpp +++ b/src/libANGLE/Program.cpp @@ -1347,6 +1347,7 @@ angle::Result Program::linkImpl(const Context *context) return angle::Result::Continue; } + mState.mExecutable->mHasDiscard = fragmentShader->hasDiscard(); mState.mExecutable->mEnablesPerSampleShading = fragmentShader->enablesPerSampleShading(); mState.mExecutable->mAdvancedBlendEquations = diff --git a/src/libANGLE/ProgramExecutable.cpp b/src/libANGLE/ProgramExecutable.cpp index fa7cc3f7b..a693321bc 100644 --- a/src/libANGLE/ProgramExecutable.cpp +++ b/src/libANGLE/ProgramExecutable.cpp @@ -196,6 +196,7 @@ ProgramExecutable::ProgramExecutable() mImageUniformRange(0, 0), mAtomicCounterUniformRange(0, 0), mFragmentInoutRange(0, 0), + mHasDiscard(false), mEnablesPerSampleShading(false), // [GL_EXT_geometry_shader] Table 20.22 mGeometryShaderInputPrimitiveType(PrimitiveMode::Triangles), @@ -244,6 +245,7 @@ ProgramExecutable::ProgramExecutable(const ProgramExecutable &other) mAtomicCounterBuffers(other.mAtomicCounterBuffers), mShaderStorageBlocks(other.mShaderStorageBlocks), mFragmentInoutRange(other.mFragmentInoutRange), + mHasDiscard(other.mHasDiscard), mEnablesPerSampleShading(other.mEnablesPerSampleShading), mAdvancedBlendEquations(other.mAdvancedBlendEquations) { @@ -293,6 +295,7 @@ void ProgramExecutable::reset(bool clearInfoLog) mAtomicCounterUniformRange = RangeUI(0, 0); mFragmentInoutRange = RangeUI(0, 0); + mHasDiscard = false; mEnablesPerSampleShading = false; mAdvancedBlendEquations.reset(); @@ -325,6 +328,7 @@ void ProgramExecutable::load(bool isSeparable, gl::BinaryInputStream *stream) unsigned int fragmentInoutRangeHigh = stream->readInt(); mFragmentInoutRange = RangeUI(fragmentInoutRangeLow, fragmentInoutRangeHigh); + mHasDiscard = stream->readBool(); mEnablesPerSampleShading = stream->readBool(); static_assert(sizeof(mAdvancedBlendEquations.bits()) == sizeof(uint32_t)); @@ -557,6 +561,7 @@ void ProgramExecutable::save(bool isSeparable, gl::BinaryOutputStream *stream) c stream->writeInt(mFragmentInoutRange.low()); stream->writeInt(mFragmentInoutRange.high()); + stream->writeBool(mHasDiscard); stream->writeBool(mEnablesPerSampleShading); stream->writeInt(mAdvancedBlendEquations.bits()); diff --git a/src/libANGLE/ProgramExecutable.h b/src/libANGLE/ProgramExecutable.h index 603ea59ba..0b049439c 100644 --- a/src/libANGLE/ProgramExecutable.h +++ b/src/libANGLE/ProgramExecutable.h @@ -231,6 +231,7 @@ class ProgramExecutable final : public angle::Subject const RangeUI &getImageUniformRange() const { return mImageUniformRange; } const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; } const RangeUI &getFragmentInoutRange() const { return mFragmentInoutRange; } + bool hasDiscard() const { return mHasDiscard; } bool enablesPerSampleShading() const { return mEnablesPerSampleShading; } BlendEquationBitSet getAdvancedBlendEquations() const { return mAdvancedBlendEquations; } const std::vector &getLinkedTransformFeedbackVaryings() const @@ -472,6 +473,7 @@ class ProgramExecutable final : public angle::Subject std::vector mShaderStorageBlocks; RangeUI mFragmentInoutRange; + bool mHasDiscard; bool mEnablesPerSampleShading; // KHR_blend_equation_advanced supported equation list diff --git a/src/libANGLE/ProgramPipeline.cpp b/src/libANGLE/ProgramPipeline.cpp index dfa0c93ef..b8b0abf80 100644 --- a/src/libANGLE/ProgramPipeline.cpp +++ b/src/libANGLE/ProgramPipeline.cpp @@ -371,6 +371,7 @@ void ProgramPipeline::updateFragmentInoutRangeAndEnablesPerSampleShading() const ProgramExecutable &fragmentExecutable = fragmentProgram->getExecutable(); mState.mExecutable->mFragmentInoutRange = fragmentExecutable.mFragmentInoutRange; + mState.mExecutable->mHasDiscard = fragmentExecutable.mHasDiscard; mState.mExecutable->mEnablesPerSampleShading = fragmentExecutable.mEnablesPerSampleShading; } diff --git a/src/libANGLE/Shader.cpp b/src/libANGLE/Shader.cpp index 928b116bd..854eefc8d 100644 --- a/src/libANGLE/Shader.cpp +++ b/src/libANGLE/Shader.cpp @@ -343,6 +343,7 @@ void Shader::compile(const Context *context) mState.mTessGenVertexOrder = 0; mState.mTessGenPointMode = 0; mState.mAdvancedBlendEquations.reset(); + mState.mHasDiscard = false; mState.mEnablesPerSampleShading = false; mState.mSpecConstUsageBits.reset(); @@ -544,6 +545,7 @@ void Shader::resolveCompile() std::sort(mState.mInputVaryings.begin(), mState.mInputVaryings.end(), CompareShaderVar); mState.mActiveOutputVariables = GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle)); + mState.mHasDiscard = sh::HasDiscardInFragmentShader(compilerHandle); mState.mEnablesPerSampleShading = sh::EnablesPerSampleShading(compilerHandle); mState.mAdvancedBlendEquations = BlendEquationBitSet(sh::GetAdvancedBlendEquations(compilerHandle)); diff --git a/src/libANGLE/Shader.h b/src/libANGLE/Shader.h index 098bf320f..62819b2e8 100644 --- a/src/libANGLE/Shader.h +++ b/src/libANGLE/Shader.h @@ -91,6 +91,7 @@ class ShaderState final : angle::NonCopyable const sh::WorkGroupSize &getLocalSize() const { return mLocalSize; } + bool hasDiscard() const { return mHasDiscard; } bool enablesPerSampleShading() const { return mEnablesPerSampleShading; } rx::SpecConstUsageBits getSpecConstUsageBits() const { return mSpecConstUsageBits; } @@ -134,6 +135,7 @@ class ShaderState final : angle::NonCopyable std::vector mActiveAttributes; std::vector mActiveOutputVariables; + bool mHasDiscard; bool mEnablesPerSampleShading; BlendEquationBitSet mAdvancedBlendEquations; rx::SpecConstUsageBits mSpecConstUsageBits; @@ -200,6 +202,7 @@ class Shader final : angle::NonCopyable, public LabeledObject unsigned int getRefCount() const; bool isFlaggedForDeletion() const; void flagForDeletion(); + bool hasDiscard() const { return mState.mHasDiscard; } bool enablesPerSampleShading() const { return mState.mEnablesPerSampleShading; } BlendEquationBitSet getAdvancedBlendEquations() const { return mState.mAdvancedBlendEquations; } rx::SpecConstUsageBits getSpecConstUsageBits() const { return mState.mSpecConstUsageBits; } diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp index 4d4d0c91a..2086d2ee5 100644 --- a/src/libANGLE/renderer/vulkan/ContextVk.cpp +++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp @@ -920,8 +920,11 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_LINE_WIDTH); mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_POLYGON_OFFSET); mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_BLEND_COLOR); - mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT); - mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK); + if (!getFeatures().useNonZeroStencilWriteMaskStaticState.enabled) + { + mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT); + mPipelineDirtyBitsMask.reset(gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK); + } // Dynamic state in VK_EXT_extended_dynamic_state: if (getFeatures().supportsExtendedDynamicState.enabled) @@ -4626,6 +4629,24 @@ void ContextVk::updateDither() } } +void ContextVk::updateStencilWriteWorkaround() +{ + if (!getFeatures().useNonZeroStencilWriteMaskStaticState.enabled) + { + return; + } + + // On certain drivers, having a stencil write mask of 0 in static state enables optimizations + // that make the interaction of the stencil write mask dynamic state with discard and alpha to + // coverage broken. When the program has discard, or when alpha to coverage is enabled, these + // optimizations are disabled by specifying a non-zero static state for stencil write mask. + const bool programHasDiscard = mState.getProgramExecutable()->hasDiscard(); + const bool isAlphaToCoverageEnabled = mState.isSampleAlphaToCoverageEnabled(); + + mGraphicsPipelineDesc->updateNonZeroStencilWriteMaskWorkaround( + &mGraphicsPipelineTransition, programHasDiscard || isAlphaToCoverageEnabled); +} + angle::Result ContextVk::invalidateProgramExecutableHelper(const gl::Context *context) { const gl::State &glState = context->getState(); @@ -4661,6 +4682,8 @@ angle::Result ContextVk::invalidateProgramExecutableHelper(const gl::Context *co // masked, so update their access. onColorAccessChange(); } + + updateStencilWriteWorkaround(); } return angle::Result::Continue; @@ -4729,6 +4752,8 @@ angle::Result ContextVk::syncState(const gl::Context *context, case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED: mGraphicsPipelineDesc->updateAlphaToCoverageEnable( &mGraphicsPipelineTransition, glState.isSampleAlphaToCoverageEnabled()); + updateStencilWriteWorkaround(); + static_assert(gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE > gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED, "Dirty bit order"); diff --git a/src/libANGLE/renderer/vulkan/ContextVk.h b/src/libANGLE/renderer/vulkan/ContextVk.h index 8a4d14df7..e7adfa5d0 100644 --- a/src/libANGLE/renderer/vulkan/ContextVk.h +++ b/src/libANGLE/renderer/vulkan/ContextVk.h @@ -1277,6 +1277,16 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText void updateDither(); + // When the useNonZeroStencilWriteMaskStaticState workaround is enabled, the static state for + // stencil should be non-zero despite the state being dynamic. This is done when: + // + // - The shader includes discard, or + // - Alpha-to-coverage is enabled. + // + // An alternative could have been to set the static state unconditionally to non-zero. This is + // avoided however, as on the affected driver that would disable certain optimizations. + void updateStencilWriteWorkaround(); + SpecConstUsageBits getCurrentProgramSpecConstUsageBits() const; void updateGraphicsPipelineDescWithSpecConstUsageBits(SpecConstUsageBits usageBits); diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp index a1f31b560..c95933ab8 100644 --- a/src/libANGLE/renderer/vulkan/RendererVk.cpp +++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp @@ -3671,6 +3671,11 @@ void RendererVk::initFeatures(DisplayVk *displayVk, !isARM && !isPowerVR && !isQualcommProprietary && !(IsLinux() && isIntel) && !(IsChromeOS() && isSwiftShader)); + // On ARM, dynamic state for stencil write mask doesn't work correctly in the presence of + // discard or alpha to coverage, if the static state provided when creating the pipeline has a + // value of 0. + ANGLE_FEATURE_CONDITION(&mFeatures, useNonZeroStencilWriteMaskStaticState, isARM); + // On ARM, per-sample shading is not enabled despite the presence of a Sample decoration. As a // workaround, per-sample shading is inferred by ANGLE and explicitly enabled by the API. ANGLE_FEATURE_CONDITION(&mFeatures, explicitlyEnablePerSampleShading, isARM); diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp index 31389b45f..de87b8483 100644 --- a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp +++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp @@ -257,14 +257,20 @@ void UnpackDepthStencilResolveAttachmentDesc(VkAttachmentDescription *desc, desc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } -void UnpackStencilState(const PackedStencilOpState &packedState, VkStencilOpState *stateOut) +void UnpackStencilState(const PackedStencilOpState &packedState, + VkStencilOpState *stateOut, + bool writeMaskWorkaround) { + // Any non-zero value works for the purposes of the useNonZeroStencilWriteMaskStaticState driver + // bug workaround. + constexpr uint32_t kNonZeroWriteMaskForWorkaround = 1; + stateOut->failOp = static_cast(packedState.ops.fail); stateOut->passOp = static_cast(packedState.ops.pass); stateOut->depthFailOp = static_cast(packedState.ops.depthFail); stateOut->compareOp = static_cast(packedState.ops.compare); stateOut->compareMask = 0; - stateOut->writeMask = 0; + stateOut->writeMask = writeMaskWorkaround ? kNonZeroWriteMaskForWorkaround : 0; stateOut->reference = 0; } @@ -1637,7 +1643,7 @@ void UnpackPipelineState(const vk::GraphicsPipelineDesc &state, UnpackedPipeline const PackedInputAssemblyAndRasterizationStateInfo &inputAndRaster = state.getInputAssemblyAndRasterizationStateInfoForLog(); const PackedColorBlendStateInfo &colorBlend = state.getColorBlendStateInfoForLog(); - const PackedDither &dither = state.getDitherForLog(); + const PackedDitherAndWorkarounds &dither = state.getDitherForLog(); const PackedDynamicState &dynamicState = state.getDynamicStateForLog(); valuesOut->fill(0); @@ -2669,8 +2675,9 @@ void GraphicsPipelineDesc::initDefaults(const ContextVk *contextVk) &mColorBlendStateInfo.attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS], blendAttachmentState); - mDither.emulatedDitherControl = 0; - mDither.unused = 0; + mDitherAndWorkarounds.emulatedDitherControl = 0; + mDitherAndWorkarounds.nonZeroStencilWriteMaskWorkaround = 0; + mDitherAndWorkarounds.unused = 0; SetBitField(mDynamicState.ds1And2.cullMode, VK_CULL_MODE_NONE); SetBitField(mDynamicState.ds1And2.frontFace, VK_FRONT_FACE_COUNTER_CLOCKWISE); @@ -3032,8 +3039,10 @@ angle::Result GraphicsPipelineDesc::initializePipeline( depthStencilState.depthBoundsTestEnable = static_cast(inputAndRaster.misc.depthBoundsTest); depthStencilState.stencilTestEnable = static_cast(mDynamicState.ds1And2.stencilTest); - UnpackStencilState(mDynamicState.ds1.front, &depthStencilState.front); - UnpackStencilState(mDynamicState.ds1.back, &depthStencilState.back); + UnpackStencilState(mDynamicState.ds1.front, &depthStencilState.front, + mDitherAndWorkarounds.nonZeroStencilWriteMaskWorkaround); + UnpackStencilState(mDynamicState.ds1.back, &depthStencilState.back, + mDitherAndWorkarounds.nonZeroStencilWriteMaskWorkaround); depthStencilState.minDepthBounds = 0; depthStencilState.maxDepthBounds = 0; @@ -3703,10 +3712,18 @@ void GraphicsPipelineDesc::updateEmulatedDitherControl(GraphicsPipelineTransitio uint16_t value) { // Make sure we don't waste time resetting this to zero in the common no-dither case. - ASSERT(value != 0 || mDither.emulatedDitherControl != 0); + ASSERT(value != 0 || mDitherAndWorkarounds.emulatedDitherControl != 0); - mDither.emulatedDitherControl = value; - transition->set(ANGLE_GET_TRANSITION_BIT(mDither, emulatedDitherControl)); + mDitherAndWorkarounds.emulatedDitherControl = value; + transition->set(ANGLE_GET_TRANSITION_BIT(mDitherAndWorkarounds, emulatedDitherControl)); +} + +void GraphicsPipelineDesc::updateNonZeroStencilWriteMaskWorkaround( + GraphicsPipelineTransitionBits *transition, + bool enabled) +{ + mDitherAndWorkarounds.nonZeroStencilWriteMaskWorkaround = enabled; + transition->set(ANGLE_GET_TRANSITION_BIT(mDitherAndWorkarounds, emulatedDitherControl)); } void GraphicsPipelineDesc::updateRenderPassDesc(GraphicsPipelineTransitionBits *transition, diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.h b/src/libANGLE/renderer/vulkan/vk_cache_utils.h index 924612d32..e2797f5db 100644 --- a/src/libANGLE/renderer/vulkan/vk_cache_utils.h +++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.h @@ -468,12 +468,13 @@ struct PackedColorBlendStateInfo final constexpr size_t kPackedColorBlendStateSize = sizeof(PackedColorBlendStateInfo); static_assert(kPackedColorBlendStateSize == 36, "Size check failed"); -struct PackedDither final +struct PackedDitherAndWorkarounds final { static_assert(gl::IMPLEMENTATION_MAX_DRAW_BUFFERS <= 8, "2 bits per draw buffer is needed for dither emulation"); uint16_t emulatedDitherControl; - uint16_t unused; + uint16_t nonZeroStencilWriteMaskWorkaround : 1; + uint16_t unused : 15; }; // State that is dynamic in VK_EXT_extended_dynamic_state and 2. These are placed at the end of the @@ -537,7 +538,7 @@ static_assert(kPackedDynamicStateSize == 40, "Size check failed"); constexpr size_t kGraphicsPipelineDescSumOfSizes = kVertexInputAttributesSize + kRenderPassDescSize + kPackedInputAssemblyAndRasterizationStateSize + kPackedColorBlendStateSize + - sizeof(PackedDither) + kPackedDynamicStateSize; + sizeof(PackedDitherAndWorkarounds) + kPackedDynamicStateSize; // Number of dirty bits in the dirty bit set. constexpr size_t kGraphicsPipelineDirtyBitBytes = 4; @@ -720,7 +721,13 @@ class GraphicsPipelineDesc final } void updateEmulatedDitherControl(GraphicsPipelineTransitionBits *transition, uint16_t value); - uint32_t getEmulatedDitherControl() const { return mDither.emulatedDitherControl; } + uint32_t getEmulatedDitherControl() const + { + return mDitherAndWorkarounds.emulatedDitherControl; + } + + void updateNonZeroStencilWriteMaskWorkaround(GraphicsPipelineTransitionBits *transition, + bool enabled); void setSupportsDynamicStateForTest(bool supports) { @@ -740,7 +747,7 @@ class GraphicsPipelineDesc final { return mColorBlendStateInfo; } - const PackedDither &getDitherForLog() const { return mDither; } + const PackedDitherAndWorkarounds &getDitherForLog() const { return mDitherAndWorkarounds; } const PackedDynamicState &getDynamicStateForLog() const { return mDynamicState; } private: @@ -750,7 +757,7 @@ class GraphicsPipelineDesc final RenderPassDesc mRenderPassDesc; PackedInputAssemblyAndRasterizationStateInfo mInputAssemblyAndRasterizationStateInfo; PackedColorBlendStateInfo mColorBlendStateInfo; - PackedDither mDither; + PackedDitherAndWorkarounds mDitherAndWorkarounds; PackedDynamicState mDynamicState; }; diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt index 03789f9a8..294cfd033 100644 --- a/src/tests/angle_end2end_tests_expectations.txt +++ b/src/tests/angle_end2end_tests_expectations.txt @@ -538,7 +538,6 @@ 7158 PIXEL6 VULKAN : ImageTestES3.SourceAHBMipTarget2DMip/* = SKIP 7158 PIXEL6 VULKAN : ImageTestES3.SourceAHBMipTarget2DMipGenerateMipmap/* = SKIP 7279 PIXEL6 VULKAN : PixelLocalStorageTest.EarlyFragmentTests/ES3_1_Vulkan_EmulatePixelLocalStorage* = SKIP -7556 PIXEL6 VULKAN : StateChangeTestES3.StencilWriteMaskVsDiscard/* = SKIP // ARM drivers cannot support xfb emulation because they lack support for the // vertexPipelineStoresAndAtomics Vulkan feature. The tests that force-enable this feature are diff --git a/util/angle_features_autogen.cpp b/util/angle_features_autogen.cpp index dcf7523b0..e6bfca848 100644 --- a/util/angle_features_autogen.cpp +++ b/util/angle_features_autogen.cpp @@ -285,6 +285,7 @@ constexpr PackedEnumMap kFeatureNames = {{ {Feature::UploadTextureDataInChunks, "uploadTextureDataInChunks"}, {Feature::UseInstancedPointSpriteEmulation, "useInstancedPointSpriteEmulation"}, {Feature::UseMultipleDescriptorsForExternalFormats, "useMultipleDescriptorsForExternalFormats"}, + {Feature::UseNonZeroStencilWriteMaskStaticState, "useNonZeroStencilWriteMaskStaticState"}, {Feature::UseSystemMemoryForConstantBuffers, "useSystemMemoryForConstantBuffers"}, {Feature::UseUnusedBlocksWithStandardOrSharedLayout, "useUnusedBlocksWithStandardOrSharedLayout"}, diff --git a/util/angle_features_autogen.h b/util/angle_features_autogen.h index 13655e9ef..c022152df 100644 --- a/util/angle_features_autogen.h +++ b/util/angle_features_autogen.h @@ -266,6 +266,7 @@ enum class Feature UploadTextureDataInChunks, UseInstancedPointSpriteEmulation, UseMultipleDescriptorsForExternalFormats, + UseNonZeroStencilWriteMaskStaticState, UseSystemMemoryForConstantBuffers, UseUnusedBlocksWithStandardOrSharedLayout, VertexIDDoesNotIncludeBaseVertex,