From 05506bb874891e0001437a20e51ffadb5d409314 Mon Sep 17 00:00:00 2001 From: amhagan Date: Tue, 13 Jun 2017 16:53:02 -0400 Subject: [PATCH] Implement the extension GL_AMD_shader_fragment_mask --- SPIRV/GLSL.ext.AMD.h | 10 +- SPIRV/GlslangToSpv.cpp | 43 +++++- SPIRV/doc.cpp | 13 ++ .../spv.shaderFragMaskAMD.frag.out | 123 ++++++++++++++++++ Test/spv.shaderFragMaskAMD.frag | 29 +++++ glslang/Include/BaseTypes.h | 2 + glslang/Include/intermediate.h | 16 +++ glslang/MachineIndependent/Initialize.cpp | 47 ++++++- glslang/MachineIndependent/Versions.cpp | 2 + glslang/MachineIndependent/Versions.h | 1 + glslang/MachineIndependent/intermOut.cpp | 9 +- gtests/Spv.FromFile.cpp | 1 + 12 files changed, 288 insertions(+), 8 deletions(-) create mode 100644 Test/baseResults/spv.shaderFragMaskAMD.frag.out create mode 100644 Test/spv.shaderFragMaskAMD.frag diff --git a/SPIRV/GLSL.ext.AMD.h b/SPIRV/GLSL.ext.AMD.h index 5121ed99..7e97be38 100644 --- a/SPIRV/GLSL.ext.AMD.h +++ b/SPIRV/GLSL.ext.AMD.h @@ -33,7 +33,7 @@ enum Decoration; enum Op; static const int GLSLextAMDVersion = 100; -static const int GLSLextAMDRevision = 5; +static const int GLSLextAMDRevision = 6; // SPV_AMD_shader_ballot static const char* const E_SPV_AMD_shader_ballot = "SPV_AMD_shader_ballot"; @@ -106,4 +106,12 @@ static const char* const E_SPV_AMD_shader_image_load_store_lod = "SPV_AMD_shader static const Capability CapabilityImageReadWriteLodAMD = static_cast(5015); +// SPV_AMD_shader_fragment_mask +static const char* const E_SPV_AMD_shader_fragment_mask = "SPV_AMD_shader_fragment_mask"; + +static const Capability CapabilityFragmentMaskAMD = static_cast(5010); + +static const Op OpFragmentMaskFetchAMD = static_cast(5011); +static const Op OpFragmentFetchAMD = static_cast(5012); + #endif // #ifndef GLSLextAMD_H diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index a82867a4..bd244630 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -3204,9 +3204,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO glslang::TCrackedTextureOp cracked; node->crackTexture(sampler, cracked); - const bool isUnsignedResult = - node->getType().getBasicType() == glslang::EbtUint64 || - node->getType().getBasicType() == glslang::EbtUint; + const bool isUnsignedResult = node->getType().getBasicType() == glslang::EbtUint; // Check for queries if (cracked.query) { @@ -3358,6 +3356,45 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO } } +#ifdef AMD_EXTENSIONS + // Check for fragment mask functions other than queries + if (cracked.fragMask) { + assert(sampler.ms); + + auto opIt = arguments.begin(); + std::vector operands; + + // Extract the image if necessary + if (builder.isSampledImage(params.sampler)) + params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler); + + operands.push_back(params.sampler); + ++opIt; + + if (sampler.isSubpass()) { + // add on the (0,0) coordinate + spv::Id zero = builder.makeIntConstant(0); + std::vector comps; + comps.push_back(zero); + comps.push_back(zero); + operands.push_back(builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps)); + } + + for (; opIt != arguments.end(); ++opIt) + operands.push_back(*opIt); + + spv::Op fragMaskOp = spv::OpNop; + if (node->getOp() == glslang::EOpFragmentMaskFetch) + fragMaskOp = spv::OpFragmentMaskFetchAMD; + else if (node->getOp() == glslang::EOpFragmentFetch) + fragMaskOp = spv::OpFragmentFetchAMD; + + builder.addExtension(spv::E_SPV_AMD_shader_fragment_mask); + builder.addCapability(spv::CapabilityFragmentMaskAMD); + return builder.createOp(fragMaskOp, resultType(), operands); + } +#endif + // Check for texture functions other than queries bool sparse = node->isSparseTexture(); bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow; diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp index 2fe5d9ce..f9d5254c 100755 --- a/SPIRV/doc.cpp +++ b/SPIRV/doc.cpp @@ -847,6 +847,7 @@ const char* CapabilityString(int info) #ifdef AMD_EXTENSIONS case 5009: return "ImageGatherBiasLodAMD"; + case 5010: return "FragmentMaskAMD"; case 5015: return "ImageReadWriteLodAMD"; #endif @@ -1207,6 +1208,9 @@ const char* OpcodeString(int op) case 5005: return "OpGroupFMaxNonUniformAMD"; case 5006: return "OpGroupUMaxNonUniformAMD"; case 5007: return "OpGroupSMaxNonUniformAMD"; + + case 5011: return "OpFragmentMaskFetchAMD"; + case 5012: return "OpFragmentFetchAMD"; #endif case OpcodeCeiling: @@ -2869,6 +2873,15 @@ void Parameterize() InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpFragmentMaskFetchAMD].capabilities.push_back(CapabilityFragmentMaskAMD); + InstructionDesc[OpFragmentMaskFetchAMD].operands.push(OperandId, "'Image'"); + InstructionDesc[OpFragmentMaskFetchAMD].operands.push(OperandId, "'Coordinate'"); + + InstructionDesc[OpFragmentFetchAMD].capabilities.push_back(CapabilityFragmentMaskAMD); + InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Image'"); + InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Fragment Index'"); #endif } diff --git a/Test/baseResults/spv.shaderFragMaskAMD.frag.out b/Test/baseResults/spv.shaderFragMaskAMD.frag.out new file mode 100644 index 00000000..84dbcd52 --- /dev/null +++ b/Test/baseResults/spv.shaderFragMaskAMD.frag.out @@ -0,0 +1,123 @@ +spv.shaderFragMaskAMD.frag +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 80 + + Capability Shader + Capability StorageImageMultisample + Capability InputAttachment + Capability FragmentMaskAMD + Extension "SPV_AMD_shader_fragment_mask" + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 78 + ExecutionMode 4 OriginUpperLeft + Source GLSL 450 + SourceExtension "GL_AMD_shader_fragment_mask" + Name 4 "main" + Name 9 "f4" + Name 14 "fragMask" + Name 18 "s2DMS" + Name 27 "fragIndex" + Name 42 "is2DMSArray" + Name 62 "usubpassMS" + Name 78 "fragColor" + Decorate 18(s2DMS) DescriptorSet 0 + Decorate 18(s2DMS) Binding 0 + Decorate 42(is2DMSArray) DescriptorSet 0 + Decorate 42(is2DMSArray) Binding 1 + Decorate 62(usubpassMS) DescriptorSet 0 + Decorate 62(usubpassMS) Binding 2 + Decorate 62(usubpassMS) InputAttachmentIndex 0 + Decorate 78(fragColor) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypePointer Function 7(fvec4) + 10: 6(float) Constant 0 + 11: 7(fvec4) ConstantComposite 10 10 10 10 + 12: TypeInt 32 0 + 13: TypePointer Function 12(int) + 15: TypeImage 6(float) 2D multi-sampled sampled format:Unknown + 16: TypeSampledImage 15 + 17: TypePointer UniformConstant 16 + 18(s2DMS): 17(ptr) Variable UniformConstant + 20: TypeInt 32 1 + 21: TypeVector 20(int) 2 + 22: 20(int) Constant 2 + 23: 20(int) Constant 3 + 24: 21(ivec2) ConstantComposite 22 23 + 29: 12(int) Constant 240 + 31: 20(int) Constant 4 + 34: 12(int) Constant 1 + 39: TypeImage 20(int) 2D array multi-sampled sampled format:Unknown + 40: TypeSampledImage 39 + 41: TypePointer UniformConstant 40 + 42(is2DMSArray): 41(ptr) Variable UniformConstant + 44: TypeVector 20(int) 3 + 45: 20(int) Constant 1 + 46: 44(ivec3) ConstantComposite 22 23 45 + 55: TypeVector 20(int) 4 + 60: TypeImage 12(int) SubpassData multi-sampled nonsampled format:Unknown + 61: TypePointer UniformConstant 60 + 62(usubpassMS): 61(ptr) Variable UniformConstant + 64: 20(int) Constant 0 + 65: 21(ivec2) ConstantComposite 64 64 + 72: TypeVector 12(int) 4 + 77: TypePointer Output 7(fvec4) + 78(fragColor): 77(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 9(f4): 8(ptr) Variable Function + 14(fragMask): 13(ptr) Variable Function + 27(fragIndex): 13(ptr) Variable Function + Store 9(f4) 11 + 19: 16 Load 18(s2DMS) + 25: 15 Image 19 + 26: 12(int) FragmentMaskFetchAMD 25 24 + Store 14(fragMask) 26 + 28: 12(int) Load 14(fragMask) + 30: 12(int) BitwiseAnd 28 29 + 32: 12(int) ShiftRightLogical 30 31 + Store 27(fragIndex) 32 + 33: 16 Load 18(s2DMS) + 35: 15 Image 33 + 36: 7(fvec4) FragmentFetchAMD 35 24 34 + 37: 7(fvec4) Load 9(f4) + 38: 7(fvec4) FAdd 37 36 + Store 9(f4) 38 + 43: 40 Load 42(is2DMSArray) + 47: 39 Image 43 + 48: 12(int) FragmentMaskFetchAMD 47 46 + Store 14(fragMask) 48 + 49: 12(int) Load 14(fragMask) + 50: 12(int) BitwiseAnd 49 29 + 51: 12(int) ShiftRightLogical 50 31 + Store 27(fragIndex) 51 + 52: 40 Load 42(is2DMSArray) + 53: 12(int) Load 27(fragIndex) + 54: 39 Image 52 + 56: 55(ivec4) FragmentFetchAMD 54 46 53 + 57: 7(fvec4) ConvertSToF 56 + 58: 7(fvec4) Load 9(f4) + 59: 7(fvec4) FAdd 58 57 + Store 9(f4) 59 + 63: 60 Load 62(usubpassMS) + 66: 12(int) FragmentMaskFetchAMD 63 65 + Store 14(fragMask) 66 + 67: 12(int) Load 14(fragMask) + 68: 12(int) BitwiseAnd 67 29 + 69: 12(int) ShiftRightLogical 68 31 + Store 27(fragIndex) 69 + 70: 60 Load 62(usubpassMS) + 71: 12(int) Load 27(fragIndex) + 73: 72(ivec4) FragmentFetchAMD 70 65 71 + 74: 7(fvec4) ConvertUToF 73 + 75: 7(fvec4) Load 9(f4) + 76: 7(fvec4) FAdd 75 74 + Store 9(f4) 76 + 79: 7(fvec4) Load 9(f4) + Store 78(fragColor) 79 + Return + FunctionEnd diff --git a/Test/spv.shaderFragMaskAMD.frag b/Test/spv.shaderFragMaskAMD.frag new file mode 100644 index 00000000..b9e8ab05 --- /dev/null +++ b/Test/spv.shaderFragMaskAMD.frag @@ -0,0 +1,29 @@ +#version 450 core + +#extension GL_AMD_shader_fragment_mask: enable + +layout(binding = 0) uniform sampler2DMS s2DMS; +layout(binding = 1) uniform isampler2DMSArray is2DMSArray; + +layout(binding = 2, input_attachment_index = 0) uniform usubpassInputMS usubpassMS; + +layout(location = 0) out vec4 fragColor; + +void main() +{ + vec4 f4 = vec4(0.0); + + uint fragMask = fragmentMaskFetchAMD(s2DMS, ivec2(2, 3)); + uint fragIndex = (fragMask & 0xF0) >> 4; + f4 += fragmentFetchAMD(s2DMS, ivec2(2, 3), 1); + + fragMask = fragmentMaskFetchAMD(is2DMSArray, ivec3(2, 3, 1)); + fragIndex = (fragMask & 0xF0) >> 4; + f4 += fragmentFetchAMD(is2DMSArray, ivec3(2, 3, 1), fragIndex); + + fragMask = fragmentMaskFetchAMD(usubpassMS); + fragIndex = (fragMask & 0xF0) >> 4; + f4 += fragmentFetchAMD(usubpassMS, fragIndex); + + fragColor = f4; +} \ No newline at end of file diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h index 08fb623a..0a46a7c0 100644 --- a/glslang/Include/BaseTypes.h +++ b/glslang/Include/BaseTypes.h @@ -198,6 +198,7 @@ enum TBuiltInVariable { EbvSamplePosition, EbvSampleMask, EbvHelperInvocation, + #ifdef AMD_EXTENSIONS EbvBaryCoordNoPersp, EbvBaryCoordNoPerspCentroid, @@ -334,6 +335,7 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v) case EbvSamplePosition: return "SamplePosition"; case EbvSampleMask: return "SampleMaskIn"; case EbvHelperInvocation: return "HelperInvocation"; + #ifdef AMD_EXTENSIONS case EbvBaryCoordNoPersp: return "BaryCoordNoPersp"; case EbvBaryCoordNoPerspCentroid: return "BaryCoordNoPerspCentroid"; diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h index 6149b19b..97e3e478 100644 --- a/glslang/Include/intermediate.h +++ b/glslang/Include/intermediate.h @@ -653,6 +653,8 @@ enum TOperator { EOpTextureGatherLod, EOpTextureGatherLodOffset, EOpTextureGatherLodOffsets, + EOpFragmentMaskFetch, + EOpFragmentFetch, #endif EOpSparseTextureGuardBegin, @@ -1032,6 +1034,9 @@ struct TCrackedTextureOp { bool grad; bool subpass; bool lodClamp; +#ifdef AMD_EXTENSIONS + bool fragMask; +#endif }; // @@ -1079,6 +1084,9 @@ public: cracked.grad = false; cracked.subpass = false; cracked.lodClamp = false; +#ifdef AMD_EXTENSIONS + cracked.fragMask = false; +#endif switch (op) { case EOpImageQuerySize: @@ -1210,6 +1218,14 @@ public: case EOpSparseImageLoadLod: cracked.lod = true; break; + case EOpFragmentMaskFetch: + cracked.subpass = sampler.dim == EsdSubpass; + cracked.fragMask = true; + break; + case EOpFragmentFetch: + cracked.subpass = sampler.dim == EsdSubpass; + cracked.fragMask = true; + break; #endif case EOpSubpassLoad: case EOpSubpassLoadMS: diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp index e71ec5ef..129e3518 100644 --- a/glslang/MachineIndependent/Initialize.cpp +++ b/glslang/MachineIndependent/Initialize.cpp @@ -2283,7 +2283,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if (profile != EEsProfile && version >= 450) { commonBuiltins.append( "float cubeFaceIndexAMD(vec3);" - "vec2 cubeFaceCoordAMD(vec3);" + "vec2 cubeFaceCoordAMD(vec3);" "uint64_t timeAMD();" "\n"); @@ -2787,6 +2787,29 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + + // GL_AMD_shader_fragment_mask + if (profile != EEsProfile && version >= 450) { + commonBuiltins.append( + "uint fragmentMaskFetchAMD(sampler2DMS, ivec2);" + "uint fragmentMaskFetchAMD(isampler2DMS, ivec2);" + "uint fragmentMaskFetchAMD(usampler2DMS, ivec2);" + + "uint fragmentMaskFetchAMD(sampler2DMSArray, ivec3);" + "uint fragmentMaskFetchAMD(isampler2DMSArray, ivec3);" + "uint fragmentMaskFetchAMD(usampler2DMSArray, ivec3);" + + "vec4 fragmentFetchAMD(sampler2DMS, ivec2, uint);" + "ivec4 fragmentFetchAMD(isampler2DMS, ivec2, uint);" + "uvec4 fragmentFetchAMD(usampler2DMS, ivec2, uint);" + + "vec4 fragmentFetchAMD(sampler2DMSArray, ivec3, uint);" + "ivec4 fragmentFetchAMD(isampler2DMSArray, ivec3, uint);" + "uvec4 fragmentFetchAMD(usampler2DMSArray, ivec3, uint);" + + "\n"); + } + #endif //============================================================================ @@ -3126,6 +3149,20 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } + + // GL_AMD_shader_fragment_mask + if (profile != EEsProfile && version >= 450 && spvVersion.vulkan >= 100) { + stageBuiltins[EShLangFragment].append( + "uint fragmentMaskFetchAMD(subpassInputMS);" + "uint fragmentMaskFetchAMD(isubpassInputMS);" + "uint fragmentMaskFetchAMD(usubpassInputMS);" + + "vec4 fragmentFetchAMD(subpassInputMS, uint);" + "ivec4 fragmentFetchAMD(isubpassInputMS, uint);" + "uvec4 fragmentFetchAMD(usubpassInputMS, uint);" + + "\n"); + } #endif //============================================================================ @@ -5372,6 +5409,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("cubeFaceCoordAMD", 1, &E_GL_AMD_gcn_shader); symbolTable.setFunctionExtensions("timeAMD", 1, &E_GL_AMD_gcn_shader); } + + if (profile != EEsProfile) { + symbolTable.setFunctionExtensions("fragmentMaskFetchAMD", 1, &E_GL_AMD_shader_fragment_mask); + symbolTable.setFunctionExtensions("fragmentFetchAMD", 1, &E_GL_AMD_shader_fragment_mask); + } #endif // Compatibility variables, vertex only @@ -6210,6 +6252,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("imageLoadLodAMD", EOpImageLoadLod); symbolTable.relateToOperator("imageStoreLodAMD", EOpImageStoreLod); symbolTable.relateToOperator("sparseImageLoadLodAMD", EOpSparseImageLoadLod); + + symbolTable.relateToOperator("fragmentMaskFetchAMD", EOpFragmentMaskFetch); + symbolTable.relateToOperator("fragmentFetchAMD", EOpFragmentFetch); #endif } if (profile == EEsProfile) { diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp index 531aa159..c4329e60 100644 --- a/glslang/MachineIndependent/Versions.cpp +++ b/glslang/MachineIndependent/Versions.cpp @@ -201,6 +201,7 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_AMD_texture_gather_bias_lod] = EBhDisable; extensionBehavior[E_GL_AMD_gpu_shader_int16] = EBhDisable; extensionBehavior[E_GL_AMD_shader_image_load_store_lod] = EBhDisable; + extensionBehavior[E_GL_AMD_shader_fragment_mask] = EBhDisable; #endif #ifdef NV_EXTENSIONS @@ -333,6 +334,7 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_AMD_texture_gather_bias_lod 1\n" "#define GL_AMD_gpu_shader_int16 1\n" "#define GL_AMD_shader_image_load_store_lod 1\n" + "#define GL_AMD_shader_fragment_mask 1\n" #endif #ifdef NV_EXTENSIONS diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h index 78a9b286..d5aca70e 100644 --- a/glslang/MachineIndependent/Versions.h +++ b/glslang/MachineIndependent/Versions.h @@ -171,6 +171,7 @@ const char* const E_GL_AMD_gpu_shader_half_float = "GL_AMD_gpu_sh const char* const E_GL_AMD_texture_gather_bias_lod = "GL_AMD_texture_gather_bias_lod"; const char* const E_GL_AMD_gpu_shader_int16 = "GL_AMD_gpu_shader_int16"; const char* const E_GL_AMD_shader_image_load_store_lod = "GL_AMD_shader_image_load_store_lod"; +const char* const E_GL_AMD_shader_fragment_mask = "GL_AMD_shader_fragment_mask"; #endif #ifdef NV_EXTENSIONS diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp index 30240fcc..ae68216a 100644 --- a/glslang/MachineIndependent/intermOut.cpp +++ b/glslang/MachineIndependent/intermOut.cpp @@ -431,10 +431,13 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpMaxInvocationsExclusiveScanNonUniform: out.debug << "maxInvocationsExclusiveScanNonUniform"; break; case EOpAddInvocationsExclusiveScanNonUniform: out.debug << "addInvocationsExclusiveScanNonUniform"; break; - case EOpMbcnt: out.debug << "mbcnt"; break; + case EOpMbcnt: out.debug << "mbcnt"; break; - case EOpCubeFaceIndex: out.debug << "cubeFaceIndex"; break; - case EOpCubeFaceCoord: out.debug << "cubeFaceCoord"; break; + case EOpCubeFaceIndex: out.debug << "cubeFaceIndex"; break; + case EOpCubeFaceCoord: out.debug << "cubeFaceCoord"; break; + + case EOpFragmentMaskFetch: out.debug << "fragmentMaskFetchAMD"; break; + case EOpFragmentFetch: out.debug << "fragmentFetchAMD"; break; case EOpConvBoolToFloat16: out.debug << "Convert bool to float16"; break; case EOpConvIntToFloat16: out.debug << "Convert int to float16"; break; diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp index ef2ef342..4cfcf48b 100644 --- a/gtests/Spv.FromFile.cpp +++ b/gtests/Spv.FromFile.cpp @@ -409,6 +409,7 @@ INSTANTIATE_TEST_CASE_P( "spv.imageLoadStoreLod.frag", "spv.int16.frag", "spv.shaderBallotAMD.comp", + "spv.shaderFragMaskAMD.frag", "spv.textureGatherBiasLod.frag" })), FileNameAsCustomTestSuffix