Add support for indexing into arrays of image descriptors - OpLoad of pointer to descriptor is passthrough; reflect that in Kind. - Actually pass through all the descriptor types in EmitLoad - Fix Walk*AccessChain to not create useless divergence; constant offset was added in the wrong place. - Adjust WalkAccessChain to adjust pointers into descriptor arrays using the descriptor stride - Adjust storage image descriptor content to not assume layerPitch == slicePitch, since that isn't true. Bug: b/131082089 Test: dEQP-VK.binding_model.* Test: dEQP-VK.spirv_assembly.* Test: dEQP-VK.glsl.* Change-Id: I6cc4ae7b0fdeb54ede111f532c7e3fd1f108803c Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29549 Tested-by: Chris Forbes <chrisforbes@google.com> Presubmit-Ready: Chris Forbes <chrisforbes@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp index 3d71c51..be8de93 100644 --- a/src/Pipeline/SpirvShader.cpp +++ b/src/Pipeline/SpirvShader.cpp
@@ -1383,15 +1383,34 @@ case spv::OpTypeRuntimeArray: { // TODO: b/127950082: Check bounds. - auto stride = getType(type.element).sizeInComponents * sizeof(float); - auto & obj = getObject(indexIds[i]); - if (obj.kind == Object::Kind::Constant) + if (getType(baseObject.type).storageClass == spv::StorageClassUniformConstant) { - constantOffset += stride * GetConstantInt(indexIds[i]); + // indexing into an array of descriptors. + auto &obj = getObject(indexIds[i]); + if (obj.kind != Object::Kind::Constant) + { + UNIMPLEMENTED("Nonconstant indexing of descriptor arrays is not supported"); + } + + auto d = descriptorDecorations.at(baseId); + ASSERT(d.DescriptorSet >= 0); + ASSERT(d.Binding >= 0); + auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet); + auto stride = setLayout->getBindingStride(d.Binding); + ptr.base += stride * GetConstantInt(indexIds[i]); } else { - ptr.addOffset(SIMD::Int(stride) * routine->getIntermediate(indexIds[i]).Int(0)); + auto stride = getType(type.element).sizeInComponents * sizeof(float); + auto & obj = getObject(indexIds[i]); + if (obj.kind == Object::Kind::Constant) + { + constantOffset += stride * GetConstantInt(indexIds[i]); + } + else + { + ptr.addOffset(SIMD::Int(stride) * routine->getIntermediate(indexIds[i]).Int(0)); + } } typeId = type.element; break; @@ -1404,7 +1423,7 @@ if (constantOffset != 0) { - ptr.addOffset(SIMD::Int(constantOffset)); + ptr.addOffset(constantOffset); } return ptr; } @@ -1598,8 +1617,20 @@ Object::ID resultId = insn.word(2); auto &object = defs[resultId]; object.type = typeId; - object.kind = (getType(typeId).opcode() == spv::OpTypePointer) - ? Object::Kind::DivergentPointer : Object::Kind::Intermediate; + + switch (getType(typeId).opcode()) + { + case spv::OpTypePointer: + case spv::OpTypeImage: + case spv::OpTypeSampledImage: + case spv::OpTypeSampler: + object.kind = Object::Kind::DivergentPointer; + break; + + default: + object.kind = Object::Kind::Intermediate; + } + object.definition = insn; } @@ -2302,7 +2333,7 @@ ASSERT(Type::ID(insn.word(1)) == result.type); ASSERT(!atomic || getType(getType(pointer.type).element).opcode() == spv::OpTypeInt); // Vulkan 1.1: "Atomic instructions must declare a scalar 32-bit integer type, for the value pointed to by Pointer." - if(pointer.kind == Object::Kind::SampledImage) + if(pointerTy.storageClass == spv::StorageClassUniformConstant) { // Just propagate the pointer. // TODO(b/129523279) @@ -4358,12 +4389,7 @@ Pointer<Byte> constants; // FIXME(b/129523279) - const DescriptorDecorations &d = descriptorDecorations.at(sampledImageId); - uint32_t arrayIndex = 0; // TODO(b/129523279) - auto setLayout = state->routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet); - size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex); - - auto descriptor = state->routine->descriptorSets[d.DescriptorSet] + bindingOffset; // vk::SampledImageDescriptor* + auto descriptor = sampledImage.base; // vk::SampledImageDescriptor* auto sampler = *Pointer<Pointer<Byte>>(descriptor + OFFSET(vk::SampledImageDescriptor, sampler)); // vk::Sampler* auto imageView = *Pointer<Pointer<Byte>>(descriptor + OFFSET(vk::SampledImageDescriptor, imageView)); // vk::ImageView* @@ -4469,7 +4495,9 @@ auto coordinate = GenericValue(this, state->routine, insn.word(4)); - Pointer<Byte> binding = state->routine->getPointer(imageId).base; + auto pointer = state->routine->getPointer(imageId); + ASSERT(pointer.uniform); + Pointer<Byte> binding = pointer.base; Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr)); auto &dst = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp index ded7cd0..3367b8d 100644 --- a/src/Vulkan/VkDescriptorSetLayout.cpp +++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -176,6 +176,12 @@ return bindingCount; } +size_t DescriptorSetLayout::getBindingStride(uint32_t binding) const +{ + uint32_t index = getBindingIndex(binding); + return GetDescriptorSize(bindings[index].descriptorType); +} + size_t DescriptorSetLayout::getBindingOffset(uint32_t binding, size_t arrayElement) const { uint32_t index = getBindingIndex(binding); @@ -442,7 +448,9 @@ 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].slicePitchBytes = imageView->getSubresourceRange().layerCount > 1 + ? imageView->layerPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT) + : imageView->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0); descriptor[i].arrayLayers = imageView->getSubresourceRange().layerCount; } }
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp index 621e13f..05e074a 100644 --- a/src/Vulkan/VkDescriptorSetLayout.hpp +++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -70,6 +70,9 @@ // the given binding and array element within that binding. size_t getBindingOffset(uint32_t binding, size_t arrayElement) const; + // Returns the stride of an array of descriptors + size_t getBindingStride(uint32_t binding) const; + // Returns the number of descriptors across all bindings that are dynamic // (see isBindingDynamic). uint32_t getDynamicDescriptorCount() const;
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp index 0ad40a5..0ac2c9a 100644 --- a/src/Vulkan/VkImage.hpp +++ b/src/Vulkan/VkImage.hpp
@@ -67,6 +67,7 @@ void* getTexelPointer(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const; bool isCube() const; uint8_t* end() const; + VkDeviceSize getLayerSize(VkImageAspectFlagBits aspect) const; static Format GetFormat(const vk::Format& format, VkImageAspectFlagBits aspect); @@ -75,7 +76,6 @@ VkDeviceSize getStorageSize(VkImageAspectFlags flags) const; VkDeviceSize getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const; VkDeviceSize getMultiSampledLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const; - VkDeviceSize getLayerSize(VkImageAspectFlagBits aspect) const; VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const; VkDeviceSize getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const; VkDeviceSize texelOffsetBytesInStorage(const VkOffset3D& offset, const VkImageSubresourceLayers& subresource) const;
diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp index 4e54f8a..70311a5 100644 --- a/src/Vulkan/VkImageView.hpp +++ b/src/Vulkan/VkImageView.hpp
@@ -41,6 +41,7 @@ int getSampleCount() const { return image->getSampleCountFlagBits(); } int rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const { return image->rowPitchBytes(aspect, subresourceRange.baseMipLevel + mipLevel); } int slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const { return image->slicePitchBytes(aspect, subresourceRange.baseMipLevel + mipLevel); } + int layerPitchBytes(VkImageAspectFlagBits aspect) const { return static_cast<int>(image->getLayerSize(aspect)); } VkExtent3D getMipLevelExtent(uint32_t mipLevel) const { return image->getMipLevelExtent(subresourceRange.baseMipLevel + mipLevel); } void *getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect) const;