Commit efec1b9f by Ben Clayton

SpirvShader: Implement Uniform and StorageBuffer access

Bug: b/126330097 Change-Id: Ia612ddf785b79b88a59c30b1e436470bb3fba3e8 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/26228Reviewed-by: 's avatarChris Forbes <chrisforbes@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent 831db96b
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <spirv/unified1/spirv.hpp> #include <spirv/unified1/spirv.hpp>
#include "SpirvShader.hpp" #include "SpirvShader.hpp"
#include "System/Math.hpp" #include "System/Math.hpp"
#include "Vulkan/VkBuffer.hpp"
#include "Vulkan/VkDebug.hpp" #include "Vulkan/VkDebug.hpp"
#include "Vulkan/VkPipelineLayout.hpp" #include "Vulkan/VkPipelineLayout.hpp"
#include "Device/Config.hpp" #include "Device/Config.hpp"
...@@ -154,10 +155,36 @@ namespace sw ...@@ -154,10 +155,36 @@ namespace sw
object.type = typeId; object.type = typeId;
object.pointerBase = insn.word(2); // base is itself object.pointerBase = insn.word(2); // base is itself
// Register builtins ASSERT(getType(typeId).storageClass == storageClass);
if (storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput)
switch (storageClass)
{ {
case spv::StorageClassInput:
case spv::StorageClassOutput:
ProcessInterfaceVariable(object); 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; break;
} }
...@@ -1036,15 +1063,43 @@ namespace sw ...@@ -1036,15 +1063,43 @@ namespace sw
ObjectID resultId = insn.word(2); ObjectID resultId = insn.word(2);
auto &object = getObject(resultId); auto &object = getObject(resultId);
auto &objectTy = getType(object.type); auto &objectTy = getType(object.type);
if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassInput) switch (objectTy.storageClass)
{ {
auto &dst = routine->getValue(resultId); case spv::StorageClassInput:
int offset = 0; {
VisitInterface(resultId, if (object.kind == Object::Kind::InterfaceVariable)
[&](Decorations const &d, AttribType type) { {
auto scalarSlot = d.Location << 2 | d.Component; auto &dst = routine->getValue(resultId);
dst[offset++] = routine->inputs[scalarSlot]; 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 @@ namespace sw ...@@ -1061,11 +1116,9 @@ namespace sw
ASSERT(getType(pointer.type).element == object.type); ASSERT(getType(pointer.type).element == object.type);
ASSERT(TypeID(insn.word(1)) == object.type); ASSERT(TypeID(insn.word(1)) == object.type);
if (pointerBaseTy.storageClass == spv::StorageClassImage || if (pointerBaseTy.storageClass == spv::StorageClassImage)
pointerBaseTy.storageClass == spv::StorageClassUniform ||
pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
{ {
UNIMPLEMENTED("Descriptor-backed load not yet implemented"); UNIMPLEMENTED("StorageClassImage load not yet implemented");
} }
Pointer<Float> ptrBase; Pointer<Float> ptrBase;
...@@ -1125,17 +1178,9 @@ namespace sw ...@@ -1125,17 +1178,9 @@ namespace sw
ObjectID baseId = insn.word(3); ObjectID baseId = insn.word(3);
auto &object = getObject(objectId); auto &object = getObject(objectId);
auto &type = getType(typeId); auto &type = getType(typeId);
auto &pointerBase = getObject(object.pointerBase);
auto &pointerBaseTy = getType(pointerBase.type);
ASSERT(type.sizeInComponents == 1); ASSERT(type.sizeInComponents == 1);
ASSERT(getObject(baseId).pointerBase == object.pointerBase); 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); auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine))); dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
} }
...@@ -1151,11 +1196,9 @@ namespace sw ...@@ -1151,11 +1196,9 @@ namespace sw
auto &pointerBase = getObject(pointer.pointerBase); auto &pointerBase = getObject(pointer.pointerBase);
auto &pointerBaseTy = getType(pointerBase.type); auto &pointerBaseTy = getType(pointerBase.type);
if (pointerBaseTy.storageClass == spv::StorageClassImage || if (pointerBaseTy.storageClass == spv::StorageClassImage)
pointerBaseTy.storageClass == spv::StorageClassUniform ||
pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
{ {
UNIMPLEMENTED("Descriptor-backed store not yet implemented"); UNIMPLEMENTED("StorageClassImage store not yet implemented");
} }
Pointer<Float> ptrBase; Pointer<Float> ptrBase;
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
namespace vk namespace vk
{ {
const size_t Buffer::DataOffset = offsetof(Buffer, memory);
Buffer::Buffer(const VkBufferCreateInfo* pCreateInfo, void* mem) : Buffer::Buffer(const VkBufferCreateInfo* pCreateInfo, void* mem) :
flags(pCreateInfo->flags), size(pCreateInfo->size), usage(pCreateInfo->usage), flags(pCreateInfo->flags), size(pCreateInfo->size), usage(pCreateInfo->usage),
sharingMode(pCreateInfo->sharingMode), queueFamilyIndexCount(pCreateInfo->queueFamilyIndexCount), sharingMode(pCreateInfo->sharingMode), queueFamilyIndexCount(pCreateInfo->queueFamilyIndexCount),
...@@ -43,21 +45,21 @@ size_t Buffer::ComputeRequiredAllocationSize(const VkBufferCreateInfo* pCreateIn ...@@ -43,21 +45,21 @@ size_t Buffer::ComputeRequiredAllocationSize(const VkBufferCreateInfo* pCreateIn
const VkMemoryRequirements Buffer::getMemoryRequirements() const const VkMemoryRequirements Buffer::getMemoryRequirements() const
{ {
VkMemoryRequirements memoryRequirements = {}; VkMemoryRequirements memoryRequirements = {};
if(usage & (VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)) if(usage & (VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT))
{ {
memoryRequirements.alignment = vk::MIN_TEXEL_BUFFER_OFFSET_ALIGNMENT; memoryRequirements.alignment = vk::MIN_TEXEL_BUFFER_OFFSET_ALIGNMENT;
} }
else if(usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) else if(usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
{ {
memoryRequirements.alignment = vk::MIN_STORAGE_BUFFER_OFFSET_ALIGNMENT; memoryRequirements.alignment = vk::MIN_STORAGE_BUFFER_OFFSET_ALIGNMENT;
} }
else if(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) else if(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
{ {
memoryRequirements.alignment = vk::MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT; memoryRequirements.alignment = vk::MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT;
} }
else else
{ {
memoryRequirements.alignment = REQUIRED_MEMORY_ALIGNMENT; memoryRequirements.alignment = REQUIRED_MEMORY_ALIGNMENT;
} }
memoryRequirements.memoryTypeBits = vk::MEMORY_TYPE_GENERIC_BIT; memoryRequirements.memoryTypeBits = vk::MEMORY_TYPE_GENERIC_BIT;
memoryRequirements.size = size; // TODO: also reserve space for a header containing memoryRequirements.size = size; // TODO: also reserve space for a header containing
......
...@@ -38,6 +38,10 @@ public: ...@@ -38,6 +38,10 @@ public:
void update(VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData); void update(VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
void* getOffsetPointer(VkDeviceSize offset) const; 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: private:
void* memory = nullptr; void* memory = nullptr;
VkBufferCreateFlags flags = 0; VkBufferCreateFlags flags = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment