diff --git a/src/dxvk/dxvk_spec_const.cpp b/src/dxvk/dxvk_spec_const.cpp
index 8af30a69..b85d57c4 100644
--- a/src/dxvk/dxvk_spec_const.cpp
+++ b/src/dxvk/dxvk_spec_const.cpp
@@ -56,5 +56,39 @@ namespace dxvk {
       m_mapEntries[MaxNumSpecConstants + MaxNumActiveBindings + constId] = entry;
     }
   }
+
+
+
+
+  DxvkSpecConstants::DxvkSpecConstants() {
+
+  }
+
+
+  DxvkSpecConstants::~DxvkSpecConstants() {
+
+  }
+
+
+  VkSpecializationInfo DxvkSpecConstants::getSpecInfo() const {
+    VkSpecializationInfo specInfo;
+    specInfo.mapEntryCount = m_map.size();
+    specInfo.pMapEntries   = m_map.data();
+    specInfo.dataSize      = m_data.size() * sizeof(uint32_t);
+    specInfo.pData         = m_data.data();
+    return specInfo;
+  }
+
+
+  void DxvkSpecConstants::setAsUint32(uint32_t specId, uint32_t value) {
+    uint32_t index = m_data.size();
+    m_data.push_back(value);
+
+    VkSpecializationMapEntry mapEntry;
+    mapEntry.constantID = specId;
+    mapEntry.offset     = sizeof(uint32_t) * index;
+    mapEntry.size       = sizeof(uint32_t);
+    m_map.push_back(mapEntry);
+  }
   
 }
\ No newline at end of file
diff --git a/src/dxvk/dxvk_spec_const.h b/src/dxvk/dxvk_spec_const.h
index 016264ac..563f8076 100644
--- a/src/dxvk/dxvk_spec_const.h
+++ b/src/dxvk/dxvk_spec_const.h
@@ -77,5 +77,51 @@ namespace dxvk {
   };
   
   extern DxvkSpecConstantMap g_specConstantMap;
+
+  /**
+   * \brief Specialization constant info
+   * 
+   * Accumulates specialization constant data for
+   * constants that use non-default values.
+   */
+  class DxvkSpecConstants {
+
+  public:
+
+    DxvkSpecConstants();
+
+    ~DxvkSpecConstants();
+
+    /**
+     * \brief Sets specialization constant value
+     *
+     * If the given value is different from the constant's
+     * default value, this will store the new value and add
+     * a map entry so that it gets applied properly. Each
+     * constant may only be set once.
+     * \param [in] specId Specialization constant ID
+     * \param [in] value Specialization constant value
+     * \param [in] defaultValue Default value
+     */
+    template<typename T>
+    void set(uint32_t specId, T value, T defaultValue) {
+      if (value != defaultValue)
+        setAsUint32(specId, uint32_t(value));
+    }
+
+    /**
+     * \brief Generates specialization info structure
+     * \returns Specialization info for shader module
+     */
+    VkSpecializationInfo getSpecInfo() const;
+
+  private:
+
+    std::vector<uint32_t>                 m_data = { };
+    std::vector<VkSpecializationMapEntry> m_map  = { };
+
+    void setAsUint32(uint32_t specId, uint32_t value);
+
+  };
   
 }
\ No newline at end of file