Refactor SPIR-V binary storage

This change introduces sw::SpirvBinary, which represents a raw SPIR-V
binary as a vector of 32-bit words. Additional utility methods are
expected to be moved from sw::SpirvShader into this class.

Bug: b/197982536
Change-Id: Ibe3b4c16f7b5c2f56c9e0a7557bedab716cfe704
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/57128
Reviewed-by: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/BUILD.gn b/src/Pipeline/BUILD.gn
index d579689..d88e255 100644
--- a/src/Pipeline/BUILD.gn
+++ b/src/Pipeline/BUILD.gn
@@ -23,6 +23,7 @@
     "SamplerCore.hpp",
     "SetupRoutine.hpp",
     "ShaderCore.hpp",
+    "SpirvBinary.hpp",
     "SpirvShader.hpp",
     "SpirvShaderDebug.hpp",
     "VertexProgram.hpp",
diff --git a/src/Pipeline/CMakeLists.txt b/src/Pipeline/CMakeLists.txt
index ba8c1f2..4daf9e1 100644
--- a/src/Pipeline/CMakeLists.txt
+++ b/src/Pipeline/CMakeLists.txt
@@ -32,6 +32,7 @@
     SetupRoutine.hpp
     ShaderCore.cpp
     ShaderCore.hpp
+    SpirvBinary.hpp
     SpirvID.hpp
     SpirvShader.cpp
     SpirvShader.hpp
diff --git a/src/Pipeline/SpirvBinary.hpp b/src/Pipeline/SpirvBinary.hpp
new file mode 100644
index 0000000..b4766bb
--- /dev/null
+++ b/src/Pipeline/SpirvBinary.hpp
@@ -0,0 +1,36 @@
+// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_SpirvBinary_hpp
+#define sw_SpirvBinary_hpp
+
+#include <cstdint>
+#include <vector>
+
+namespace sw {
+
+class SpirvBinary : public std::vector<uint32_t>
+{
+public:
+	SpirvBinary() = default;
+
+	SpirvBinary(const uint32_t *binary, uint32_t wordCount)
+	    : std::vector<uint32_t>(binary, binary + wordCount)
+	{
+	}
+};
+
+}  // namespace sw
+
+#endif  // sw_SpirvBinary_hpp
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 37ccbb3..4718c3c 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -29,7 +29,7 @@
     uint32_t codeSerialID,
     VkShaderStageFlagBits pipelineStage,
     const char *entryPointName,
-    InsnStore const &insns,
+    SpirvBinary const &insns,
     const vk::RenderPass *renderPass,
     uint32_t subpassIndex,
     bool robustBufferAccess,
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 62b885b..45bb576 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -17,6 +17,7 @@
 
 #include "SamplerCore.hpp"
 #include "ShaderCore.hpp"
+#include "SpirvBinary.hpp"
 #include "SpirvID.hpp"
 #include "Device/Config.hpp"
 #include "Device/Sampler.hpp"
@@ -152,8 +153,7 @@
 class SpirvShader
 {
 public:
-	using InsnStore = std::vector<uint32_t>;
-	InsnStore insns;
+	SpirvBinary insns;
 
 	using ImageSampler = void(void *texture, void *uvsIn, void *texelOut, void *constants);
 
@@ -173,7 +173,7 @@
 
 		InsnIterator() = default;
 
-		explicit InsnIterator(InsnStore::const_iterator iter)
+		explicit InsnIterator(SpirvBinary::const_iterator iter)
 		    : iter{ iter }
 		{
 		}
@@ -282,7 +282,7 @@
 		}
 
 	private:
-		InsnStore::const_iterator iter;
+		SpirvBinary::const_iterator iter;
 	};
 
 	/* range-based-for interface */
@@ -565,7 +565,7 @@
 	SpirvShader(uint32_t codeSerialID,
 	            VkShaderStageFlagBits stage,
 	            const char *entryPointName,
-	            InsnStore const &insns,
+	            SpirvBinary const &insns,
 	            const vk::RenderPass *renderPass,
 	            uint32_t subpassIndex,
 	            bool robustBufferAccess,
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 3901672..8ab06d9 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -33,8 +33,8 @@
 namespace {
 
 // preprocessSpirv applies and freezes specializations into constants, and inlines all functions.
-std::vector<uint32_t> preprocessSpirv(
-    std::vector<uint32_t> const &code,
+sw::SpirvBinary preprocessSpirv(
+    sw::SpirvBinary const &code,
     VkSpecializationInfo const *specializationInfo,
     bool optimize)
 {
@@ -57,14 +57,17 @@
 	if(specializationInfo)
 	{
 		std::unordered_map<uint32_t, std::vector<uint32_t>> specializations;
-		for(auto i = 0u; i < specializationInfo->mapEntryCount; ++i)
+		const uint8_t *specializationData = static_cast<const uint8_t *>(specializationInfo->pData);
+
+		for(uint32_t i = 0; i < specializationInfo->mapEntryCount; i++)
 		{
-			auto const &e = specializationInfo->pMapEntries[i];
-			auto value_ptr =
-			    static_cast<uint32_t const *>(specializationInfo->pData) + e.offset / sizeof(uint32_t);
-			specializations.emplace(e.constantID,
-			                        std::vector<uint32_t>{ value_ptr, value_ptr + e.size / sizeof(uint32_t) });
+			const VkSpecializationMapEntry &entry = specializationInfo->pMapEntries[i];
+			const uint8_t *value_ptr = specializationData + entry.offset;
+			std::vector<uint32_t> value(reinterpret_cast<const uint32_t *>(value_ptr),
+			                            reinterpret_cast<const uint32_t *>(value_ptr + entry.size));
+			specializations.emplace(entry.constantID, std::move(value));
 		}
+
 		opt.RegisterPass(spvtools::CreateSetSpecConstantDefaultValuePass(specializations));
 	}
 
@@ -85,7 +88,7 @@
 	optimizerOptions.set_validator_options(validatorOptions);
 #endif
 
-	std::vector<uint32_t> optimized;
+	sw::SpirvBinary optimized;
 	opt.Run(code.data(), code.size(), &optimized, optimizerOptions);
 
 	if(false)
diff --git a/src/Vulkan/VkPipelineCache.cpp b/src/Vulkan/VkPipelineCache.cpp
index 375334f..0aa72d6 100644
--- a/src/Vulkan/VkPipelineCache.cpp
+++ b/src/Vulkan/VkPipelineCache.cpp
@@ -13,13 +13,14 @@
 // limitations under the License.
 
 #include "VkPipelineCache.hpp"
+
 #include <cstring>
 
 namespace vk {
 
 PipelineCache::SpirvShaderKey::SpirvShaderKey(const VkShaderStageFlagBits pipelineStage,
                                               const std::string &entryPointName,
-                                              const std::vector<uint32_t> &insns,
+                                              const sw::SpirvBinary &insns,
                                               const vk::RenderPass *renderPass,
                                               const uint32_t subpassIndex,
                                               const vk::SpecializationInfo &specializationInfo)
diff --git a/src/Vulkan/VkPipelineCache.hpp b/src/Vulkan/VkPipelineCache.hpp
index 83664b6..933bfbf 100644
--- a/src/Vulkan/VkPipelineCache.hpp
+++ b/src/Vulkan/VkPipelineCache.hpp
@@ -17,6 +17,7 @@
 
 #include "VkObject.hpp"
 #include "VkSpecializationInfo.hpp"
+#include "Pipeline/SpirvBinary.hpp"
 
 #include "marl/mutex.h"
 #include "marl/tsa.h"
@@ -56,7 +57,7 @@
 	{
 		SpirvShaderKey(const VkShaderStageFlagBits pipelineStage,
 		               const std::string &entryPointName,
-		               const std::vector<uint32_t> &insns,
+		               const sw::SpirvBinary &insns,
 		               const vk::RenderPass *renderPass,
 		               const uint32_t subpassIndex,
 		               const vk::SpecializationInfo &specializationInfo);
@@ -65,7 +66,7 @@
 
 		const VkShaderStageFlagBits &getPipelineStage() const { return pipelineStage; }
 		const std::string &getEntryPointName() const { return entryPointName; }
-		const std::vector<uint32_t> &getInsns() const { return insns; }
+		const sw::SpirvBinary &getInsns() const { return insns; }
 		const vk::RenderPass *getRenderPass() const { return renderPass; }
 		uint32_t getSubpassIndex() const { return subpassIndex; }
 		const VkSpecializationInfo *getSpecializationInfo() const { return specializationInfo.get(); }
@@ -73,7 +74,7 @@
 	private:
 		const VkShaderStageFlagBits pipelineStage;
 		const std::string entryPointName;
-		const std::vector<uint32_t> insns;
+		const sw::SpirvBinary insns;
 		const vk::RenderPass *renderPass;
 		const uint32_t subpassIndex;
 		const vk::SpecializationInfo specializationInfo;
diff --git a/src/Vulkan/VkShaderModule.hpp b/src/Vulkan/VkShaderModule.hpp
index 19dc131..2081f07 100644
--- a/src/Vulkan/VkShaderModule.hpp
+++ b/src/Vulkan/VkShaderModule.hpp
@@ -16,6 +16,7 @@
 #define VK_SHADER_MODULE_HPP_
 
 #include "VkObject.hpp"
+#include "Pipeline/SpirvBinary.hpp"
 
 #include <atomic>
 #include <vector>
@@ -35,7 +36,7 @@
 	static size_t ComputeRequiredAllocationSize(const VkShaderModuleCreateInfo *pCreateInfo);
 	// TODO: reconsider boundary of ShaderModule class; try to avoid 'expose the
 	// guts' operations, and this copy.
-	std::vector<uint32_t> getCode() const { return std::vector<uint32_t>{ code, code + wordCount }; }
+	sw::SpirvBinary getCode() const { return sw::SpirvBinary(code, wordCount); }
 
 	uint32_t getSerialID() const { return serialID; }
 	static uint32_t nextSerialID() { return serialCounter++; }