spirv-writer: avoid dup OpCapability instructions

Change-Id: Iaf53d2addadd8efbb912e4f97ff426fd4182c9f3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/34002
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: David Neto <dneto@google.com>
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index b2c0a7e..2681e9a 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -357,8 +357,11 @@
 }
 
 void Builder::push_capability(uint32_t cap) {
-  capabilities_.push_back(
-      Instruction{spv::Op::OpCapability, {Operand::Int(cap)}});
+  if (capability_set_.count(cap) == 0) {
+    capability_set_.insert(cap);
+    capabilities_.push_back(
+        Instruction{spv::Op::OpCapability, {Operand::Int(cap)}});
+  }
 }
 
 void Builder::GenerateLabel(uint32_t id) {
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 7e6acbb..e50131c 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -18,6 +18,7 @@
 #include <functional>
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 #include "spirv/unified1/spirv.h"
@@ -93,7 +94,8 @@
   /// @param cb the callback to execute
   void iterate(std::function<void(const Instruction&)> cb) const;
 
-  /// Adds an instruction to the list of capabilities
+  /// Adds an instruction to the list of capabilities, if the capability
+  /// hasn't already been added.
   /// @param cap the capability to set
   void push_capability(uint32_t cap);
   /// @returns the capabilities
@@ -500,6 +502,7 @@
   std::unordered_map<uint32_t, ast::Variable*> spirv_id_to_variable_;
   std::vector<uint32_t> merge_stack_;
   std::vector<uint32_t> continue_stack_;
+  std::unordered_set<uint32_t> capability_set_;
 };
 
 }  // namespace spirv
diff --git a/src/writer/spirv/builder_test.cc b/src/writer/spirv/builder_test.cc
index 0d4a92e..fb2549f 100644
--- a/src/writer/spirv/builder_test.cc
+++ b/src/writer/spirv/builder_test.cc
@@ -45,6 +45,14 @@
   EXPECT_EQ(6u, b.id_bound());
 }
 
+TEST_F(BuilderTest, Capabilities_Dedup) {
+  b.push_capability(SpvCapabilityShader);
+  b.push_capability(SpvCapabilityShader);
+  b.push_capability(SpvCapabilityShader);
+
+  EXPECT_EQ(DumpInstructions(b.capabilities()), "OpCapability Shader\n");
+}
+
 }  // namespace
 }  // namespace spirv
 }  // namespace writer