Skip to content

Commit

Permalink
SpirvShader: Implement Uniform and StorageBuffer access
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
ben-clayton committed Mar 7, 2019
1 parent 831db96 commit efec1b9
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 41 deletions.
95 changes: 69 additions & 26 deletions src/Pipeline/SpirvShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -154,10 +155,36 @@ namespace sw
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;
}
Expand Down Expand Up @@ -1036,15 +1063,43 @@ namespace sw
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;
}
}

Expand All @@ -1061,11 +1116,9 @@ namespace sw
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;
Expand Down Expand Up @@ -1125,17 +1178,9 @@ namespace sw
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)));
}
Expand All @@ -1151,11 +1196,9 @@ namespace sw
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;
Expand Down
32 changes: 17 additions & 15 deletions src/Vulkan/VkBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -43,21 +45,21 @@ size_t Buffer::ComputeRequiredAllocationSize(const VkBufferCreateInfo* pCreateIn
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
Expand Down
4 changes: 4 additions & 0 deletions src/Vulkan/VkBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class Buffer : public Object<Buffer, VkBuffer>
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;
Expand Down

0 comments on commit efec1b9

Please sign in to comment.