layers: Validate multiple transform feedback output streams
diff --git a/layers/core_validation.h b/layers/core_validation.h
index fdf98db..c10498b 100644
--- a/layers/core_validation.h
+++ b/layers/core_validation.h
@@ -573,7 +573,7 @@
                                         shader_stage_attributes const* producer_stage, SHADER_MODULE_STATE const* consumer,
                                         spirv_inst_iter consumer_entrypoint, shader_stage_attributes const* consumer_stage) const;
     bool ValidateDecorations(SHADER_MODULE_STATE const* module) const;
-    bool ValidateTransformFeedback(SHADER_MODULE_STATE const* module, spirv_inst_iter& insn) const;
+    bool ValidateTransformFeedback(SHADER_MODULE_STATE const* src) const;
     bool ValidateShaderClock(SHADER_MODULE_STATE const* module, spirv_inst_iter& insn) const;
 
     template <typename RegionType>
diff --git a/layers/shader_validation.cpp b/layers/shader_validation.cpp
index a6abdf1..39f1212 100644
--- a/layers/shader_validation.cpp
+++ b/layers/shader_validation.cpp
@@ -2095,20 +2095,45 @@
     return skip;
 }
 
-bool CoreChecks::ValidateTransformFeedback(SHADER_MODULE_STATE const *module, spirv_inst_iter &insn) const {
+bool CoreChecks::ValidateTransformFeedback(SHADER_MODULE_STATE const *src) const {
     bool skip = false;
 
-    uint32_t opcode = insn.opcode();
-    if (opcode == spv::OpEmitStreamVertex || opcode == spv::OpEndStreamPrimitive) {
-        uint32_t stream = static_cast<uint32_t>(module->GetConstantValueById(insn.word(1)));
-        if (stream >= phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams) {
-            skip |= LogError(
-                device, "VUID-RuntimeSpirv-OpEmitStreamVertex-06310",
-                "vkCreateGraphicsPipelines(): shader uses transform feedback stream with index %" PRIu32
-                ", which is not less than VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackStreams (%" PRIu32
-                ").",
-                stream, phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams);
+    // Temp workaround to prevent false positive errors
+    // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2450
+    if (src->HasMultipleEntryPoints()) {
+        return skip;
+    }
+
+    layer_data::unordered_set<uint32_t> emitted_streams;
+    bool output_points = false;
+    for (const auto& insn : *src) {
+        const uint32_t opcode = insn.opcode();
+        if (opcode == spv::OpEmitStreamVertex) {
+            emitted_streams.emplace(static_cast<uint32_t>(src->GetConstantValueById(insn.word(1))));
         }
+        if (opcode == spv::OpEmitStreamVertex || opcode == spv::OpEndStreamPrimitive) {
+            uint32_t stream = static_cast<uint32_t>(src->GetConstantValueById(insn.word(1)));
+            if (stream >= phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams) {
+                skip |= LogError(
+                    device, "VUID-RuntimeSpirv-OpEmitStreamVertex-06310",
+                    "vkCreateGraphicsPipelines(): shader uses transform feedback stream with index %" PRIu32
+                    ", which is not less than VkPhysicalDeviceTransformFeedbackPropertiesEXT::maxTransformFeedbackStreams (%" PRIu32
+                    ").",
+                    stream, phys_dev_ext_props.transform_feedback_props.maxTransformFeedbackStreams);
+            }
+        }
+        if (opcode == spv::OpExecutionMode && insn.word(2) == spv::ExecutionModeOutputPoints) {
+            output_points = true;
+        }
+    }
+
+    const uint32_t emitted_streams_size = static_cast<uint32_t>(emitted_streams.size());
+    if (emitted_streams_size > 1 && !output_points &&
+        phys_dev_ext_props.transform_feedback_props.transformFeedbackStreamsLinesTriangles == VK_FALSE) {
+        skip |= LogError(
+            device, "VUID-RuntimeSpirv-transformFeedbackStreamsLinesTriangles-06311",
+            "vkCreateGraphicsPipelines(): shader emits to %" PRIu32 " vertex streams and VkPhysicalDeviceTransformFeedbackPropertiesEXT::transformFeedbackStreamsLinesTriangles is VK_FALSE, but execution mode is not OutputPoints.",
+                     emitted_streams_size);
     }
 
     return skip;
@@ -2326,7 +2351,6 @@
     // and mainly only checking the instruction in detail for a single operation
     uint32_t total_shared_size = 0;
     for (auto insn : *module) {
-        skip |= ValidateTransformFeedback(module, insn);
         skip |= ValidateTexelGatherOffset(module, insn);
         skip |= ValidateShaderCapabilitiesAndExtensions(module, insn);
         skip |= ValidateShaderClock(module, insn);
@@ -2340,6 +2364,7 @@
                          total_shared_size, phys_dev_props.limits.maxComputeSharedMemorySize);
     }
 
+    skip |= ValidateTransformFeedback(module);
     skip |= ValidateShaderStageWritableOrAtomicDescriptor(pStage->stage, stage_state.has_writable_descriptor,
                                                           stage_state.has_atomic_descriptor);
     skip |= ValidateShaderStageInputOutputLimits(module, pStage, pipeline, entrypoint);