Specialize descriptor contents for storage images

Bug: b/130768731
Test: dEQP-VK.image.*
Change-Id: Iebea846a5fe611aa4ad769e2fb7c636ddb5dbc4d
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29408
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj
index 7362e6f..0216c93 100644
--- a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj
+++ b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj
@@ -270,6 +270,7 @@
     <ClInclude Include="$(SolutionDir)src\Vulkan\Version.h" />

     <ClCompile Include="$(SolutionDir)src\Vulkan\VkBuffer.cpp" />

     <ClInclude Include="$(SolutionDir)src\Vulkan\VkBuffer.hpp" />

+    <ClInclude Include="$(SolutionDir)src\Vulkan\VkBufferView.cpp" />

     <ClInclude Include="$(SolutionDir)src\Vulkan\VkBufferView.hpp" />

     <ClCompile Include="$(SolutionDir)src\Vulkan\VkCommandBuffer.cpp" />

     <ClInclude Include="$(SolutionDir)src\Vulkan\VkCommandBuffer.hpp" />

diff --git a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters
index 2e5abaa..6d4eb0e 100644
--- a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters
+++ b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters
@@ -118,6 +118,9 @@
     <ClCompile Include="$(SolutionDir)src\Vulkan\VkBuffer.cpp">

       <Filter>src\Vulkan</Filter>

     </ClCompile>

+    <ClCompile Include="$(SolutionDir)src\Vulkan\VkBufferView.cpp">

+      <Filter>src\Vulkan</Filter>

+    </ClCompile>

     <ClCompile Include="$(SolutionDir)src\Vulkan\VkCommandBuffer.cpp">

       <Filter>src\Vulkan</Filter>

     </ClCompile>

diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 031bbf1..0e272cc 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -17,6 +17,7 @@
 #include "SamplerCore.hpp"
 #include "System/Math.hpp"
 #include "Vulkan/VkBuffer.hpp"
+#include "Vulkan/VkBufferView.hpp"
 #include "Vulkan/VkDebug.hpp"
 #include "Vulkan/VkDescriptorSet.hpp"
 #include "Vulkan/VkPipelineLayout.hpp"
@@ -280,7 +281,7 @@
 				auto &d = memberDecorations[targetId];
 				if (memberIndex >= d.size())
 					d.resize(memberIndex + 1);    // on demand; exact size would require another pass...
-				
+
 				d[memberIndex].Apply(decoration, value);
 
 				if (decoration == spv::DecorationCentroid)
diff --git a/src/Vulkan/VkBufferView.cpp b/src/Vulkan/VkBufferView.cpp
new file mode 100644
index 0000000..168f2ac
--- /dev/null
+++ b/src/Vulkan/VkBufferView.cpp
@@ -0,0 +1,40 @@
+// Copyright 2019 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.
+
+#include "VkBufferView.hpp"
+#include "VkBuffer.hpp"
+#include "VkFormat.h"
+
+namespace vk
+{
+
+BufferView::BufferView(const VkBufferViewCreateInfo* pCreateInfo, void* mem) :
+    buffer(pCreateInfo->buffer), format(pCreateInfo->format), offset(pCreateInfo->offset)
+{
+    if (pCreateInfo->range == VK_WHOLE_SIZE)
+    {
+        range = Cast(pCreateInfo->buffer)->getSize() - offset;
+    }
+    else
+    {
+        range = pCreateInfo->range - offset;
+    }
+}
+
+void * BufferView::getPointer() const
+{
+    return Cast(buffer)->getOffsetPointer(offset);
+}
+
+}
\ No newline at end of file
diff --git a/src/Vulkan/VkBufferView.hpp b/src/Vulkan/VkBufferView.hpp
index e7fc734..db68bb6 100644
--- a/src/Vulkan/VkBufferView.hpp
+++ b/src/Vulkan/VkBufferView.hpp
@@ -16,6 +16,7 @@
 #define VK_BUFFER_VIEW_HPP_
 
 #include "VkObject.hpp"
+#include "VkFormat.h"
 
 namespace vk
 {
@@ -23,11 +24,7 @@
 class BufferView : public Object<BufferView, VkBufferView>
 {
 public:
-	BufferView(const VkBufferViewCreateInfo* pCreateInfo, void* mem) :
-		buffer(pCreateInfo->buffer), format(pCreateInfo->format), offset(pCreateInfo->offset), range(pCreateInfo->range)
-	{
-	}
-
+	BufferView(const VkBufferViewCreateInfo* pCreateInfo, void* mem);
 	~BufferView() = delete;
 
 	static size_t ComputeRequiredAllocationSize(const VkBufferViewCreateInfo* pCreateInfo)
@@ -35,6 +32,9 @@
 		return 0;
 	}
 
+	void *getPointer() const;
+	uint32_t getElementCount() const { return range / Format(format).bytes(); }
+
 private:
 	VkBuffer     buffer;
 	VkFormat     format;
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index 106e3f2..ded7cd0 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -17,6 +17,7 @@
 #include "VkDescriptorSet.hpp"
 #include "VkSampler.hpp"
 #include "VkImageView.hpp"
+#include "VkBufferView.hpp"
 #include "System/Types.hpp"
 
 #include <algorithm>
@@ -95,10 +96,11 @@
 	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
 		return sizeof(SampledImageDescriptor);
 	case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+	case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+		return sizeof(StorageImageDescriptor);
 	case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
 		return sizeof(VkDescriptorImageInfo);
 	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
-	case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
 		return sizeof(VkBufferView);
 	case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
 	case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
@@ -244,19 +246,18 @@
 	case VK_DESCRIPTOR_TYPE_SAMPLER:
 	case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
 	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
-	case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
 	case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
 		return reinterpret_cast<const uint8_t*>(writeDescriptorSet.pImageInfo);
 	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
-	case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
 		return reinterpret_cast<const uint8_t*>(writeDescriptorSet.pTexelBufferView);
-		break;
 	case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
 	case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
 	case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
 	case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
 		return reinterpret_cast<const uint8_t*>(writeDescriptorSet.pBufferInfo);
-		break;
+	case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+	case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+		ASSERT("descriptorType has custom handling");
 	default:
 		UNIMPLEMENTED("descriptorType");
 		return nullptr;
@@ -432,6 +433,32 @@
 			}
 		}
 	}
+	else if (writeDescriptorSet.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
+	{
+		auto descriptor = reinterpret_cast<StorageImageDescriptor *>(memToWrite);
+		for(uint32_t i = 0; i < writeDescriptorSet.descriptorCount; i++)
+		{
+			auto imageView = vk::Cast(writeDescriptorSet.pImageInfo[i].imageView);
+			descriptor[i].ptr = imageView->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_COLOR_BIT);
+			descriptor[i].extent = imageView->getMipLevelExtent(0);
+			descriptor[i].rowPitchBytes = imageView->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+			descriptor[i].slicePitchBytes = imageView->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+			descriptor[i].arrayLayers = imageView->getSubresourceRange().layerCount;
+		}
+	}
+	else if (writeDescriptorSet.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
+	{
+		auto descriptor = reinterpret_cast<StorageImageDescriptor *>(memToWrite);
+		for (uint32_t i = 0; i < writeDescriptorSet.descriptorCount; i++)
+		{
+			auto bufferView = vk::Cast(writeDescriptorSet.pTexelBufferView[i]);
+			descriptor[i].ptr = bufferView->getPointer();
+			descriptor[i].extent = {bufferView->getElementCount(), 1, 1};
+			descriptor[i].rowPitchBytes = 0;
+			descriptor[i].slicePitchBytes = 0;
+			descriptor[i].arrayLayers = 1;
+		}
+	}
 	else
 	{
 		// If the dstBinding has fewer than descriptorCount array elements remaining
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp
index 6ccd12e..621e13f 100644
--- a/src/Vulkan/VkDescriptorSetLayout.hpp
+++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -36,6 +36,15 @@
 	sw::Texture texture;
 };
 
+struct StorageImageDescriptor
+{
+	void *ptr;
+	VkExtent3D extent;
+	int rowPitchBytes;
+	int slicePitchBytes;
+	int arrayLayers;
+};
+
 class DescriptorSetLayout : public Object<DescriptorSetLayout, VkDescriptorSetLayout>
 {
 public:
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp
index b5e3c0a..b403fb2 100644
--- a/src/Vulkan/VkImageView.cpp
+++ b/src/Vulkan/VkImageView.cpp
@@ -103,7 +103,7 @@
 	if(!format.isCompatible(image->getFormat()))
 	{
 		UNIMPLEMENTED("incompatible formats");
-	}

+	}
 
 	VkImageSubresourceRange sr;
 	sr.aspectMask = aspectMask;
diff --git a/src/Vulkan/vulkan.vcxproj b/src/Vulkan/vulkan.vcxproj
index b11ece5..59e8098 100644
--- a/src/Vulkan/vulkan.vcxproj
+++ b/src/Vulkan/vulkan.vcxproj
@@ -110,6 +110,7 @@
     <ClCompile Include="libVulkan.cpp" />

     <ClCompile Include="main.cpp" />

     <ClCompile Include="VkBuffer.cpp" />

+    <ClCompile Include="VkBufferView.cpp" />

     <ClCompile Include="VkCommandBuffer.cpp" />

     <ClCompile Include="VkCommandPool.cpp" />

     <ClCompile Include="VkDebug.cpp" />

diff --git a/src/Vulkan/vulkan.vcxproj.filters b/src/Vulkan/vulkan.vcxproj.filters
index 3b95e02..9c99109 100644
--- a/src/Vulkan/vulkan.vcxproj.filters
+++ b/src/Vulkan/vulkan.vcxproj.filters
@@ -174,6 +174,9 @@
     <ClCompile Include="VkBuffer.cpp">

       <Filter>Source Files\Vulkan</Filter>

     </ClCompile>

+    <ClCompile Include="VkBufferView.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

     <ClCompile Include="VkCommandBuffer.cpp">

       <Filter>Source Files\Vulkan</Filter>

     </ClCompile>