SpirvShader: Implement Uniform and StorageBuffer access
Bug: b/126330097
Change-Id: Ia612ddf785b79b88a59c30b1e436470bb3fba3e8
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/26228
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index ff5d7d6..0e2a6f8 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -15,6 +15,7 @@
#include <spirv/unified1/spirv.hpp>
#include "SpirvShader.hpp"
#include "System/Math.hpp"
+#include "Vulkan/VkBuffer.hpp"
#include "Vulkan/VkDebug.hpp"
#include "Vulkan/VkPipelineLayout.hpp"
#include "Device/Config.hpp"
@@ -154,10 +155,36 @@
object.type = typeId;
object.pointerBase = insn.word(2); // base is itself
- // Register builtins
- if (storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput)
+ ASSERT(getType(typeId).storageClass == storageClass);
+
+ switch (storageClass)
{
+ case spv::StorageClassInput:
+ case spv::StorageClassOutput:
ProcessInterfaceVariable(object);
+ break;
+ case spv::StorageClassUniform:
+ case spv::StorageClassStorageBuffer:
+ object.kind = Object::Kind::PhysicalPointer;
+ break;
+
+ case spv::StorageClassPrivate:
+ case spv::StorageClassFunction:
+ break; // Correctly handled.
+
+ case spv::StorageClassUniformConstant:
+ case spv::StorageClassWorkgroup:
+ case spv::StorageClassCrossWorkgroup:
+ case spv::StorageClassGeneric:
+ case spv::StorageClassPushConstant:
+ case spv::StorageClassAtomicCounter:
+ case spv::StorageClassImage:
+ UNIMPLEMENTED("StorageClass %d not yet implemented", (int)storageClass);
+ break;
+
+ default:
+ UNREACHABLE("Unexpected StorageClass"); // See Appendix A of the Vulkan spec.
+ break;
}
break;
}
@@ -1036,15 +1063,43 @@
ObjectID resultId = insn.word(2);
auto &object = getObject(resultId);
auto &objectTy = getType(object.type);
- if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassInput)
+ switch (objectTy.storageClass)
{
- auto &dst = routine->getValue(resultId);
- int offset = 0;
- VisitInterface(resultId,
- [&](Decorations const &d, AttribType type) {
- auto scalarSlot = d.Location << 2 | d.Component;
- dst[offset++] = routine->inputs[scalarSlot];
- });
+ case spv::StorageClassInput:
+ {
+ if (object.kind == Object::Kind::InterfaceVariable)
+ {
+ auto &dst = routine->getValue(resultId);
+ int offset = 0;
+ VisitInterface(resultId,
+ [&](Decorations const &d, AttribType type) {
+ auto scalarSlot = d.Location << 2 | d.Component;
+ dst[offset++] = routine->inputs[scalarSlot];
+ });
+ }
+ break;
+ }
+ case spv::StorageClassUniform:
+ case spv::StorageClassStorageBuffer:
+ {
+ Decorations d{};
+ ApplyDecorationsForId(&d, resultId);
+ ASSERT(d.DescriptorSet >= 0);
+ ASSERT(d.Binding >= 0);
+
+ size_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding);
+
+ Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
+ Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo*
+ Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(binding + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer*
+ Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void*
+ Int offset = *Pointer<Int>(binding + OFFSET(VkDescriptorBufferInfo, offset));
+ Pointer<Byte> address = data + offset;
+ routine->physicalPointers[resultId] = address;
+ break;
+ }
+ default:
+ break;
}
}
@@ -1061,11 +1116,9 @@
ASSERT(getType(pointer.type).element == object.type);
ASSERT(TypeID(insn.word(1)) == object.type);
- if (pointerBaseTy.storageClass == spv::StorageClassImage ||
- pointerBaseTy.storageClass == spv::StorageClassUniform ||
- pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
+ if (pointerBaseTy.storageClass == spv::StorageClassImage)
{
- UNIMPLEMENTED("Descriptor-backed load not yet implemented");
+ UNIMPLEMENTED("StorageClassImage load not yet implemented");
}
Pointer<Float> ptrBase;
@@ -1125,17 +1178,9 @@
ObjectID baseId = insn.word(3);
auto &object = getObject(objectId);
auto &type = getType(typeId);
- auto &pointerBase = getObject(object.pointerBase);
- auto &pointerBaseTy = getType(pointerBase.type);
ASSERT(type.sizeInComponents == 1);
ASSERT(getObject(baseId).pointerBase == object.pointerBase);
- if (pointerBaseTy.storageClass == spv::StorageClassImage ||
- pointerBaseTy.storageClass == spv::StorageClassUniform ||
- pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
- {
- UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
- }
auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
}
@@ -1151,11 +1196,9 @@
auto &pointerBase = getObject(pointer.pointerBase);
auto &pointerBaseTy = getType(pointerBase.type);
- if (pointerBaseTy.storageClass == spv::StorageClassImage ||
- pointerBaseTy.storageClass == spv::StorageClassUniform ||
- pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
+ if (pointerBaseTy.storageClass == spv::StorageClassImage)
{
- UNIMPLEMENTED("Descriptor-backed store not yet implemented");
+ UNIMPLEMENTED("StorageClassImage store not yet implemented");
}
Pointer<Float> ptrBase;
diff --git a/src/Vulkan/VkBuffer.cpp b/src/Vulkan/VkBuffer.cpp
index 6b12067..421a4a0 100644
--- a/src/Vulkan/VkBuffer.cpp
+++ b/src/Vulkan/VkBuffer.cpp
@@ -21,6 +21,8 @@
namespace vk
{
+const size_t Buffer::DataOffset = offsetof(Buffer, memory);
+
Buffer::Buffer(const VkBufferCreateInfo* pCreateInfo, void* mem) :
flags(pCreateInfo->flags), size(pCreateInfo->size), usage(pCreateInfo->usage),
sharingMode(pCreateInfo->sharingMode), queueFamilyIndexCount(pCreateInfo->queueFamilyIndexCount),
@@ -43,21 +45,21 @@
const VkMemoryRequirements Buffer::getMemoryRequirements() const
{
VkMemoryRequirements memoryRequirements = {};
- if(usage & (VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT))
- {
- memoryRequirements.alignment = vk::MIN_TEXEL_BUFFER_OFFSET_ALIGNMENT;
- }
- else if(usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
- {
- memoryRequirements.alignment = vk::MIN_STORAGE_BUFFER_OFFSET_ALIGNMENT;
- }
- else if(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
- {
- memoryRequirements.alignment = vk::MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT;
- }
- else
- {
- memoryRequirements.alignment = REQUIRED_MEMORY_ALIGNMENT;
+ if(usage & (VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT))
+ {
+ memoryRequirements.alignment = vk::MIN_TEXEL_BUFFER_OFFSET_ALIGNMENT;
+ }
+ else if(usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
+ {
+ memoryRequirements.alignment = vk::MIN_STORAGE_BUFFER_OFFSET_ALIGNMENT;
+ }
+ else if(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
+ {
+ memoryRequirements.alignment = vk::MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT;
+ }
+ else
+ {
+ memoryRequirements.alignment = REQUIRED_MEMORY_ALIGNMENT;
}
memoryRequirements.memoryTypeBits = vk::MEMORY_TYPE_GENERIC_BIT;
memoryRequirements.size = size; // TODO: also reserve space for a header containing
diff --git a/src/Vulkan/VkBuffer.hpp b/src/Vulkan/VkBuffer.hpp
index 19dfc55..255b0f1 100644
--- a/src/Vulkan/VkBuffer.hpp
+++ b/src/Vulkan/VkBuffer.hpp
@@ -38,6 +38,10 @@
void update(VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
void* getOffsetPointer(VkDeviceSize offset) const;
+ // DataOffset is the offset in bytes from the Buffer to the pointer to the
+ // buffer's data memory.
+ static const size_t DataOffset;
+
private:
void* memory = nullptr;
VkBufferCreateFlags flags = 0;