SPV: Support the new OpCode - OpImageSparseRead
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 864902c..becb3b4 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -2087,7 +2087,7 @@
 
     glslang::TSampler sampler = {};
     bool cubeCompare = false;
-    if (node.isTexture()) {
+    if (node.isTexture() || node.isImage()) {
         sampler = glslangArguments[0]->getAsTyped()->getType().getSampler();
         cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
     }
@@ -2110,6 +2110,10 @@
             if (i == 0)
                 lvalue = true;
             break;
+        case glslang::EOpSparseImageLoad:
+            if ((sampler.ms && i == 3) || (! sampler.ms && i == 2))
+                lvalue = true;
+            break;
         case glslang::EOpSparseTexture:
             if ((cubeCompare && i == 3) || (! cubeCompare && i == 2))
                 lvalue = true;
@@ -2253,9 +2257,9 @@
                 operands.push_back(spv::ImageOperandsSampleMask);
                 operands.push_back(*opIt);
             }
-            return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands);
             if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown)
                 builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
+            return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands);
         } else if (node->getOp() == glslang::EOpImageStore) {
             if (sampler.ms) {
                 operands.push_back(*(opIt + 1));
@@ -2267,9 +2271,27 @@
             if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown)
                 builder.addCapability(spv::CapabilityStorageImageWriteWithoutFormat);
             return spv::NoResult;
-        } else if (node->isSparseImage()) {
-            spv::MissingFunctionality("sparse image functions");
-            return spv::NoResult;
+        } else if (node->getOp() == glslang::EOpSparseImageLoad) {
+            builder.addCapability(spv::CapabilitySparseResidency);
+            if (builder.getImageTypeFormat(builder.getImageType(operands.front())) == spv::ImageFormatUnknown)
+                builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
+
+            if (sampler.ms) {
+                operands.push_back(spv::ImageOperandsSampleMask);
+                operands.push_back(*opIt++);
+            }
+
+            // Create the return type that was a special structure
+            spv::Id texelOut = *opIt;
+            spv::Id typeId0 = convertGlslangToSpvType(node->getType());
+            spv::Id typeId1 = builder.getDerefTypeId(texelOut);
+            spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1);
+
+            spv::Id resultId = builder.createOp(spv::OpImageSparseRead, resultTypeId, operands);
+
+            // Decode the return type
+            builder.createStore(builder.createCompositeExtract(resultId, typeId1, 1), texelOut);
+            return builder.createCompositeExtract(resultId, typeId0, 0);
         } else {
             // Process image atomic operations
 
diff --git a/Test/baseResults/spv.sparseTexture.frag.out b/Test/baseResults/spv.sparseTexture.frag.out
index 8b794a4..315e1bb 100644
--- a/Test/baseResults/spv.sparseTexture.frag.out
+++ b/Test/baseResults/spv.sparseTexture.frag.out
@@ -7,7 +7,7 @@
 
 // Module Version 10000
 // Generated by (magic number): 80001
-// Id's are bound by 399
+// Id's are bound by 433
 
                               Capability Shader
                               Capability SampledRect
@@ -15,7 +15,7 @@
                               Capability SampledCubeArray
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint Fragment 4  "main" 33 48 89 360 384
+                              EntryPoint Fragment 4  "main" 33 48 89 360 388 400 418
                               ExecutionMode 4 OriginUpperLeft
                               Source GLSL 450
                               SourceExtension  "GL_ARB_sparse_texture2"
@@ -44,7 +44,12 @@
                               Name 256  "sCubeShadow"
                               Name 289  "s2DRectShadow"
                               Name 360  "offsets"
-                              Name 384  "outColor"
+                              Name 385  "i2D"
+                              Name 388  "ic2"
+                              Name 397  "ii3D"
+                              Name 400  "ic3"
+                              Name 409  "i2DMS"
+                              Name 418  "outColor"
                               Decorate 29(s2D) DescriptorSet 0
                               Decorate 44(s3D) DescriptorSet 0
                               Decorate 59(isCube) DescriptorSet 0
@@ -58,6 +63,11 @@
                               Decorate 256(sCubeShadow) DescriptorSet 0
                               Decorate 289(s2DRectShadow) DescriptorSet 0
                               Decorate 360(offsets) Flat
+                              Decorate 385(i2D) DescriptorSet 0
+                              Decorate 388(ic2) Flat
+                              Decorate 397(ii3D) DescriptorSet 0
+                              Decorate 400(ic3) Flat
+                              Decorate 409(i2DMS) DescriptorSet 0
                2:             TypeVoid
                3:             TypeFunction 2
                6:             TypeInt 32 1
@@ -162,16 +172,29 @@
              358:             TypeArray 143(ivec2) 357
              359:             TypePointer Input 358
     360(offsets):    359(ptr) Variable Input
-             383:             TypePointer Output 11(fvec4)
-   384(outColor):    383(ptr) Variable Output
-             387:             TypeBool
+             383:             TypeImage 10(float) 2D nonsampled format:Rgba32f
+             384:             TypePointer UniformConstant 383
+        385(i2D):    384(ptr) Variable UniformConstant
+             387:             TypePointer Input 143(ivec2)
+        388(ic2):    387(ptr) Variable Input
+             395:             TypeImage 6(int) 3D nonsampled format:Rgba32i
+             396:             TypePointer UniformConstant 395
+       397(ii3D):    396(ptr) Variable UniformConstant
+             399:             TypePointer Input 129(ivec3)
+        400(ic3):    399(ptr) Variable Input
+             407:             TypeImage 10(float) 2D multi-sampled nonsampled format:Rgba32f
+             408:             TypePointer UniformConstant 407
+      409(i2DMS):    408(ptr) Variable UniformConstant
+             417:             TypePointer Output 11(fvec4)
+   418(outColor):    417(ptr) Variable Output
+             421:             TypeBool
          4(main):           2 Function None 3
                5:             Label
      8(resident):      7(ptr) Variable Function
        13(texel):     12(ptr) Variable Function
       18(itexel):     17(ptr) Variable Function
       23(utexel):     22(ptr) Variable Function
-             385:     12(ptr) Variable Function
+             419:     12(ptr) Variable Function
                               Store 8(resident) 9
                               Store 13(texel) 15
                               Store 18(itexel) 19
@@ -515,24 +538,51 @@
              381:      6(int) Load 8(resident)
              382:      6(int) BitwiseOr 381 380
                               Store 8(resident) 382
-             386:      6(int) Load 8(resident)
-             388:   387(bool) ImageSparseTexelsResident 386
-                              SelectionMerge 390 None
-                              BranchConditional 388 389 392
-             389:               Label
-             391:   11(fvec4)   Load 13(texel)
-                                Store 385 391
-                                Branch 390
-             392:               Label
-             393:   16(ivec4)   Load 18(itexel)
-             394:   11(fvec4)   ConvertSToF 393
-             395:   21(ivec4)   Load 23(utexel)
-             396:   11(fvec4)   ConvertUToF 395
-             397:   11(fvec4)   FAdd 394 396
-                                Store 385 397
-                                Branch 390
-             390:             Label
-             398:   11(fvec4) Load 385
-                              Store 384(outColor) 398
+             386:         383 Load 385(i2D)
+             389:  143(ivec2) Load 388(ic2)
+             390: 35(ResType) ImageSparseRead 386 389
+             391:   11(fvec4) CompositeExtract 390 1
+                              Store 13(texel) 391
+             392:      6(int) CompositeExtract 390 0
+             393:      6(int) Load 8(resident)
+             394:      6(int) BitwiseOr 393 392
+                              Store 8(resident) 394
+             398:         395 Load 397(ii3D)
+             401:  129(ivec3) Load 400(ic3)
+             402: 62(ResType) ImageSparseRead 398 401
+             403:   16(ivec4) CompositeExtract 402 1
+                              Store 18(itexel) 403
+             404:      6(int) CompositeExtract 402 0
+             405:      6(int) Load 8(resident)
+             406:      6(int) BitwiseOr 405 404
+                              Store 8(resident) 406
+             410:         407 Load 409(i2DMS)
+             411:  143(ivec2) Load 388(ic2)
+             412: 35(ResType) ImageSparseRead 410 411 Sample 144
+             413:   11(fvec4) CompositeExtract 412 1
+                              Store 13(texel) 413
+             414:      6(int) CompositeExtract 412 0
+             415:      6(int) Load 8(resident)
+             416:      6(int) BitwiseOr 415 414
+                              Store 8(resident) 416
+             420:      6(int) Load 8(resident)
+             422:   421(bool) ImageSparseTexelsResident 420
+                              SelectionMerge 424 None
+                              BranchConditional 422 423 426
+             423:               Label
+             425:   11(fvec4)   Load 13(texel)
+                                Store 419 425
+                                Branch 424
+             426:               Label
+             427:   16(ivec4)   Load 18(itexel)
+             428:   11(fvec4)   ConvertSToF 427
+             429:   21(ivec4)   Load 23(utexel)
+             430:   11(fvec4)   ConvertUToF 429
+             431:   11(fvec4)   FAdd 428 430
+                                Store 419 431
+                                Branch 424
+             424:             Label
+             432:   11(fvec4) Load 419
+                              Store 418(outColor) 432
                               Return
                               FunctionEnd
diff --git a/Test/spv.sparseTexture.frag b/Test/spv.sparseTexture.frag
index e4aefc5..c995ee2 100644
--- a/Test/spv.sparseTexture.frag
+++ b/Test/spv.sparseTexture.frag
@@ -16,10 +16,17 @@
 uniform usamplerCubeArray       usCubeArray;

 uniform usampler2DRect          us2DRect;

 

+layout(rgba32f) uniform image2D i2D;

+layout(rgba32i) uniform iimage3D ii3D;

+layout(rgba32f) uniform image2DMS i2DMS;

+

 in vec2 c2;

 in vec3 c3;

 in vec4 c4;

 

+in flat ivec2 ic2;

+in flat ivec3 ic3;

+

 in flat ivec2 offsets[4];

 

 out vec4 outColor;

@@ -70,11 +77,15 @@
 

     resident |= sparseTextureGatherOffsetARB(s2D, c2, ivec2(4), texel);

     resident |= sparseTextureGatherOffsetARB(is2DArray, c3, ivec2(5), itexel, 2);

-    resident |= sparseTextureGatherOffsetARB(s2DRectShadow, c2, 2.0, ivec2(7), texel); 

+    resident |= sparseTextureGatherOffsetARB(s2DRectShadow, c2, 2.0, ivec2(7), texel);

 

     resident |= sparseTextureGatherOffsetsARB(s2D, c2, offsets, texel);

     resident |= sparseTextureGatherOffsetsARB(is2DArray, c3, offsets, itexel, 2);

-    resident |= sparseTextureGatherOffsetsARB(s2DRectShadow, c2, 2.0, offsets, texel); 

+    resident |= sparseTextureGatherOffsetsARB(s2DRectShadow, c2, 2.0, offsets, texel);

+

+    resident |= sparseImageLoadARB(i2D, ic2, texel);

+    resident |= sparseImageLoadARB(ii3D, ic3, itexel);

+    resident |= sparseImageLoadARB(i2DMS, ic2, 3, texel);

 

     outColor = sparseTexelsResidentARB(resident) ? texel : vec4(itexel) + vec4(utexel);

 }
\ No newline at end of file