0003-Add-support-for-SPV_NV_shader_image_footprint
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 4911920..842582f 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -3668,6 +3668,25 @@
                 lvalue = true;
             break;
 #endif
+#ifdef NV_EXTENSIONS
+        case glslang::EOpImageSampleFootprintNV:
+            if (i == 4)
+                lvalue = true;
+            break;
+        case glslang::EOpImageSampleFootprintClampNV:
+        case glslang::EOpImageSampleFootprintLodNV:
+            if (i == 5)
+                lvalue = true;
+            break;
+        case glslang::EOpImageSampleFootprintGradNV:
+            if (i == 6)
+                lvalue = true;
+            break;
+        case glslang::EOpImageSampleFootprintGradClampNV:
+            if (i == 7)
+                lvalue = true;
+            break;
+#endif
         default:
             break;
         }
@@ -4020,6 +4039,10 @@
 
     // Check for texture functions other than queries
     bool sparse = node->isSparseTexture();
+#ifdef NV_EXTENSIONS
+    bool imageFootprint = node->isImageFootprint();
+#endif
+
     bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
 
     // check for bias argument
@@ -4049,7 +4072,12 @@
             ++nonBiasArgCount;
         if (sparse)
             ++nonBiasArgCount;
-
+#ifdef NV_EXTENSIONS
+        if (imageFootprint)
+            //Following three extra arguments
+            // int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
+            nonBiasArgCount += 3;
+#endif
         if ((int)arguments.size() > nonBiasArgCount)
             bias = true;
     }
@@ -4142,7 +4170,6 @@
         params.lodClamp = arguments[2 + extraArgs];
         ++extraArgs;
     }
-
     // sparse
     if (sparse) {
         params.texelOut = arguments[2 + extraArgs];
@@ -4158,13 +4185,81 @@
         } else
             params.component = builder.makeIntConstant(0);
     }
-
+#ifdef NV_EXTENSIONS
+    spv::Id  resultStruct = spv::NoResult;
+    if (imageFootprint) {
+        //Following three extra arguments
+        // int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
+        params.granularity = arguments[2 + extraArgs];
+        params.coarse = arguments[3 + extraArgs];
+        resultStruct = arguments[4 + extraArgs];
+        extraArgs += 3;
+    }
+#endif
     // bias
     if (bias) {
         params.bias = arguments[2 + extraArgs];
         ++extraArgs;
     }
 
+#ifdef NV_EXTENSIONS
+    if (imageFootprint) {
+        builder.addExtension(spv::E_SPV_NV_shader_image_footprint);
+        builder.addCapability(spv::CapabilityImageFootprintNV);
+
+
+        //resultStructType(OpenGL type) contains 5 elements:
+        //struct gl_TextureFootprint2DNV {
+        //    uvec2 anchor;
+        //    uvec2 offset;
+        //    uvec2 mask;
+        //    uint  lod;
+        //    uint  granularity;
+        //};
+        //or
+        //struct gl_TextureFootprint3DNV {
+        //    uvec3 anchor;
+        //    uvec3 offset;
+        //    uvec2 mask;
+        //    uint  lod;
+        //    uint  granularity;
+        //};
+        spv::Id resultStructType = builder.getContainedTypeId(builder.getTypeId(resultStruct));
+        assert(builder.isStructType(resultStructType));
+
+        //resType (SPIR-V type) contains 6 elements:
+        //Member 0 must be a Boolean type scalar(LOD), 
+        //Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor),  
+        //Member 2 must be a vector of integer type, whose Signedness operand is 0(offset), 
+        //Member 3 must be a vector of integer type, whose Signedness operand is 0(mask), 
+        //Member 4 must be a scalar of integer type, whose Signedness operand is 0(lod),
+        //Member 5 must be a scalar of integer type, whose Signedness operand is 0(granularity).
+        std::vector<spv::Id> members;
+        members.push_back(resultType());
+        for (int i = 0; i < 5; i++) {
+            members.push_back(builder.getContainedTypeId(resultStructType, i));
+        }
+        spv::Id resType = builder.makeStructType(members, "ResType");
+
+        //call ImageFootprintNV
+        spv::Id res = builder.createTextureCall(precision, resType, sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params);
+        
+        //copy resType (SPIR-V type) to resultStructType(OpenGL type)
+        for (int i = 0; i < 5; i++) {
+            builder.clearAccessChain();
+            builder.setAccessChainLValue(resultStruct);
+
+            //Accessing to a struct we created, no coherent flag is set
+            spv::Builder::AccessChain::CoherentFlags flags;
+            flags.clear();
+
+            builder.accessChainPush(builder.makeIntConstant(i), flags);
+            builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1), i+1));
+        }
+        return builder.createCompositeExtract(res, resultType(), 0);
+    }
+#endif
+
     // projective component (might not to move)
     // GLSL: "The texture coordinates consumed from P, not including the last component of P,
     //       are divided by the last component of P."