layers: Skip spirv-opt when not needed

Only call spirv-opt to flatten group decorations when there
are actually group decoration instructions (which most frontends
don't actually generate).

Change-Id: I7043ca2e16be83862d8d11353a59742ec4c72d46
diff --git a/layers/shader_validation.h b/layers/shader_validation.h
index 230adc1..bb5a895 100644
--- a/layers/shader_validation.h
+++ b/layers/shader_validation.h
@@ -20,6 +20,7 @@
 #ifndef VULKAN_SHADER_VALIDATION_H
 #define VULKAN_SHADER_VALIDATION_H
 
+#include <SPIRV/spirv.hpp>
 #include <spirv_tools_commit_id.h>
 #include "spirv-tools/optimizer.hpp"
 
@@ -79,11 +80,46 @@
     uint32_t gpu_validation_shader_id;
 
     std::vector<uint32_t> PreprocessShaderBinary(uint32_t *src_binary, size_t binary_size, spv_target_env env) {
-        spvtools::Optimizer optimizer(env);
-        optimizer.RegisterPass(spvtools::CreateFlattenDecorationPass());
-        std::vector<uint32_t> optimized_binary;
-        auto result = optimizer.Run(src_binary, binary_size / sizeof(uint32_t), &optimized_binary);
-        return (result ? optimized_binary : std::vector<uint32_t>(src_binary, src_binary + binary_size / sizeof(uint32_t)));
+        std::vector<uint32_t> src(src_binary, src_binary + binary_size / sizeof(uint32_t));
+
+        // Check if there are any group decoration instructions, and flatten them if found.
+        bool has_group_decoration = false;
+        bool done = false;
+
+        // Walk through the first part of the SPIR-V module, looking for group decoration instructions.
+        // Skip the header (5 words).
+        auto itr = spirv_inst_iter(src.begin(), src.begin() + 5);
+        auto itrend = spirv_inst_iter(src.begin(), src.end());
+        while (itr != itrend && !done) {
+            spv::Op opcode = (spv::Op)itr.opcode();
+            switch (opcode) {
+                case spv::OpDecorationGroup:
+                case spv::OpGroupDecorate:
+                case spv::OpGroupMemberDecorate:
+                    has_group_decoration = true;
+                    done = true;
+                    break;
+                case spv::OpFunction:
+                    // An OpFunction indicates there are no more decorations
+                    done = true;
+                    break;
+                default:
+                    break;
+            }
+            itr++;
+        }
+
+        if (has_group_decoration) {
+            spvtools::Optimizer optimizer(env);
+            optimizer.RegisterPass(spvtools::CreateFlattenDecorationPass());
+            std::vector<uint32_t> optimized_binary;
+            auto result = optimizer.Run(src_binary, binary_size / sizeof(uint32_t), &optimized_binary);
+            if (result) {
+                return optimized_binary;
+            }
+        }
+        // Return the original module.
+        return src;
     }
 
     shader_module(VkShaderModuleCreateInfo const *pCreateInfo, VkShaderModule shaderModule, spv_target_env env,