Refactor image query instructions OpImageQuerySize[Lod] SPIR-V instructions were previously implemented by storing both the image depth and layer count in the descriptor. Since 3D textures can't be arrayed, we only need one field. Also avoid the division by 6 for cube array layers in the instruction implementation, by performing it during the descriptor update instead. This reflects a similar change made by https://swiftshader-review.googlesource.com/c/SwiftShader/+/47388 Bug: b/162315264 Change-Id: Iaa787e6c131eec2da7e4a404743ef722423305d5 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/47688 Presubmit-Ready: Nicolas Capens <nicolascapens@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Tested-by: Nicolas Capens <nicolascapens@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Pipeline/SpirvShaderImage.cpp b/src/Pipeline/SpirvShaderImage.cpp index 59316c7..efd62fa 100644 --- a/src/Pipeline/SpirvShaderImage.cpp +++ b/src/Pipeline/SpirvShaderImage.cpp
@@ -374,62 +374,58 @@ ASSERT(imageType.definition.opcode() == spv::OpTypeImage); bool isArrayed = imageType.definition.word(5) != 0; - bool isCubeMap = imageType.definition.word(3) == spv::DimCube; + uint32_t dimensions = resultTy.componentCount - (isArrayed ? 1 : 0); const DescriptorDecorations &d = descriptorDecorations.at(imageId); auto descriptorType = routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding); Pointer<Byte> descriptor = state->getPointer(imageId).base; - Pointer<Int> extent; - Int arrayLayers; + Int width; + Int height; + Int depth; switch(descriptorType) { case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - { - extent = descriptor + OFFSET(vk::StorageImageDescriptor, extent); // int[3]* - arrayLayers = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, arrayLayers)); // uint32_t + width = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, width)); + height = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, height)); + depth = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, depth)); break; - } case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - { - extent = descriptor + OFFSET(vk::SampledImageDescriptor, extent); // int[3]* - arrayLayers = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, arrayLayers)); // uint32_t + width = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, width)); + height = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, height)); + depth = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, depth)); break; - } default: UNREACHABLE("Image descriptorType: %d", int(descriptorType)); } - auto dimensions = resultTy.componentCount - (isArrayed ? 1 : 0); - std::vector<Int> out; if(lodId != 0) { auto lodVal = Operand(this, state, lodId); ASSERT(lodVal.componentCount == 1); auto lod = lodVal.Int(0); auto one = SIMD::Int(1); - for(uint32_t i = 0; i < dimensions; i++) - { - dst.move(i, Max(SIMD::Int(extent[i]) >> lod, one)); - } + + if(dimensions >= 1) dst.move(0, Max(SIMD::Int(width) >> lod, one)); + if(dimensions >= 2) dst.move(1, Max(SIMD::Int(height) >> lod, one)); + if(dimensions >= 3) dst.move(2, Max(SIMD::Int(depth) >> lod, one)); } else { - for(uint32_t i = 0; i < dimensions; i++) - { - dst.move(i, SIMD::Int(extent[i])); - } + + if(dimensions >= 1) dst.move(0, SIMD::Int(width)); + if(dimensions >= 2) dst.move(1, SIMD::Int(height)); + if(dimensions >= 3) dst.move(2, SIMD::Int(depth)); } if(isArrayed) { - auto numElements = isCubeMap ? (arrayLayers / 6) : RValue<Int>(arrayLayers); - dst.move(dimensions, SIMD::Int(numElements)); + dst.move(dimensions, SIMD::Int(depth)); } } @@ -570,20 +566,20 @@ // Other out-of-bounds behaviors work properly by just comparing the offset against the total size. if(outOfBoundsBehavior == OutOfBoundsBehavior::Nullify) { - auto width = SIMD::UInt(*Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, extent.width))); + SIMD::UInt width = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, width)); SIMD::Int oobMask = As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(u), width)); if(dims > 1) { - auto height = SIMD::UInt(*Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, extent.height))); + SIMD::UInt height = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, height)); oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(v), height)); } if((dims > 2) || isArrayed) { - auto depth = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, extent.depth)); - auto arrayLayers = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, arrayLayers)); - oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(w), SIMD::UInt(depth * arrayLayers))); // TODO: Precompute extent. 3D image can't have layers. + UInt depth = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, depth)); + if(dim == spv::DimCube) { depth *= 6; } + oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(w), SIMD::UInt(depth))); } if(sampleId.value())
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp index 27fbde8..6959fd7 100644 --- a/src/Vulkan/VkDescriptorSetLayout.cpp +++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -264,7 +264,7 @@ if(entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) { - SampledImageDescriptor *imageSampler = reinterpret_cast<SampledImageDescriptor *>(memToWrite); + SampledImageDescriptor *sampledImage = reinterpret_cast<SampledImageDescriptor *>(memToWrite); for(uint32_t i = 0; i < entry.descriptorCount; i++) { @@ -273,37 +273,38 @@ // descriptorCount of zero, must all either use immutable samplers or must all not use immutable samplers." if(!binding.immutableSamplers) { - imageSampler[i].updateSampler(vk::Cast(update->sampler)); + sampledImage[i].updateSampler(vk::Cast(update->sampler)); } - imageSampler[i].device = device; + sampledImage[i].device = device; } } else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) { - SampledImageDescriptor *imageSampler = reinterpret_cast<SampledImageDescriptor *>(memToWrite); + SampledImageDescriptor *sampledImage = reinterpret_cast<SampledImageDescriptor *>(memToWrite); for(uint32_t i = 0; i < entry.descriptorCount; i++) { auto update = reinterpret_cast<VkBufferView const *>(src + entry.offset + entry.stride * i); auto bufferView = vk::Cast(*update); - imageSampler[i].type = VK_IMAGE_VIEW_TYPE_1D; - imageSampler[i].imageViewId = bufferView->id; - imageSampler[i].swizzle = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; - imageSampler[i].format = bufferView->getFormat(); + sampledImage[i].type = VK_IMAGE_VIEW_TYPE_1D; + sampledImage[i].imageViewId = bufferView->id; + sampledImage[i].swizzle = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; + sampledImage[i].format = bufferView->getFormat(); auto numElements = bufferView->getElementCount(); - imageSampler[i].extent = { numElements, 1, 1 }; - imageSampler[i].arrayLayers = 1; - imageSampler[i].mipLevels = 1; - imageSampler[i].sampleCount = 1; - imageSampler[i].texture.widthWidthHeightHeight = sw::float4(static_cast<float>(numElements), static_cast<float>(numElements), 1, 1); - imageSampler[i].texture.width = sw::float4(static_cast<float>(numElements)); - imageSampler[i].texture.height = sw::float4(1); - imageSampler[i].texture.depth = sw::float4(1); - imageSampler[i].device = device; + sampledImage[i].width = numElements; + sampledImage[i].height = 1; + sampledImage[i].depth = 1; + sampledImage[i].mipLevels = 1; + sampledImage[i].sampleCount = 1; + sampledImage[i].texture.widthWidthHeightHeight = sw::float4(static_cast<float>(numElements), static_cast<float>(numElements), 1, 1); + sampledImage[i].texture.width = sw::float4(static_cast<float>(numElements)); + sampledImage[i].texture.height = sw::float4(1); + sampledImage[i].texture.depth = sw::float4(1); + sampledImage[i].device = device; - sw::Mipmap &mipmap = imageSampler[i].texture.mipmap[0]; + sw::Mipmap &mipmap = sampledImage[i].texture.mipmap[0]; mipmap.buffer = bufferView->getPointer(); mipmap.width[0] = mipmap.width[1] = mipmap.width[2] = mipmap.width[3] = numElements; mipmap.height[0] = mipmap.height[1] = mipmap.height[2] = mipmap.height[3] = 1; @@ -317,16 +318,16 @@ else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || entry.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - SampledImageDescriptor *imageSampler = reinterpret_cast<SampledImageDescriptor *>(memToWrite); + SampledImageDescriptor *sampledImage = reinterpret_cast<SampledImageDescriptor *>(memToWrite); for(uint32_t i = 0; i < entry.descriptorCount; i++) { - auto update = reinterpret_cast<VkDescriptorImageInfo const *>(src + entry.offset + entry.stride * i); + auto *update = reinterpret_cast<VkDescriptorImageInfo const *>(src + entry.offset + entry.stride * i); vk::ImageView *imageView = vk::Cast(update->imageView); Format format = imageView->getFormat(ImageView::SAMPLING); - sw::Texture *texture = &imageSampler[i].texture; + sw::Texture *texture = &sampledImage[i].texture; if(entry.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) { @@ -334,20 +335,23 @@ // descriptorCount of zero, must all either use immutable samplers or must all not use immutable samplers." if(!binding.immutableSamplers) { - imageSampler[i].updateSampler(vk::Cast(update->sampler)); + sampledImage[i].updateSampler(vk::Cast(update->sampler)); } } - imageSampler[i].imageViewId = imageView->id; - imageSampler[i].extent = imageView->getMipLevelExtent(0); - imageSampler[i].arrayLayers = imageView->getSubresourceRange().layerCount; - imageSampler[i].mipLevels = imageView->getSubresourceRange().levelCount; - imageSampler[i].sampleCount = imageView->getSampleCount(); - imageSampler[i].type = imageView->getType(); - imageSampler[i].swizzle = imageView->getComponentMapping(); - imageSampler[i].format = format; - imageSampler[i].device = device; - imageSampler[i].memoryOwner = imageView; + const auto &extent = imageView->getMipLevelExtent(0); + + sampledImage[i].imageViewId = imageView->id; + sampledImage[i].width = extent.width; + sampledImage[i].height = extent.height; + sampledImage[i].depth = imageView->getDepthOrLayerCount(0); + sampledImage[i].mipLevels = imageView->getSubresourceRange().levelCount; + sampledImage[i].sampleCount = imageView->getSampleCount(); + sampledImage[i].type = imageView->getType(); + sampledImage[i].swizzle = imageView->getComponentMapping(); + sampledImage[i].format = format; + sampledImage[i].device = device; + sampledImage[i].memoryOwner = imageView; auto &subresourceRange = imageView->getSubresourceRange(); @@ -410,12 +414,11 @@ int width = extent.width; int height = extent.height; - int layers = imageView->getSubresourceRange().layerCount; - int depth = layers > 1 ? layers : extent.depth; - if(imageView->getType() == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) depth /= 6; + int layerCount = imageView->getSubresourceRange().layerCount; + int depth = imageView->getDepthOrLayerCount(level); int bytes = format.bytes(); int pitchP = imageView->rowPitchBytes(aspect, level, ImageView::SAMPLING) / bytes; - int sliceP = (layers > 1 ? imageView->layerPitchBytes(aspect, ImageView::SAMPLING) : imageView->slicePitchBytes(aspect, level, ImageView::SAMPLING)) / bytes; + int sliceP = (layerCount > 1 ? imageView->layerPitchBytes(aspect, ImageView::SAMPLING) : imageView->slicePitchBytes(aspect, level, ImageView::SAMPLING)) / bytes; int samplePitchP = imageView->getMipLevelSize(aspect, level, ImageView::SAMPLING) / bytes; int sampleMax = imageView->getSampleCount() - 1; @@ -427,49 +430,54 @@ else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || entry.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) { - auto descriptor = reinterpret_cast<StorageImageDescriptor *>(memToWrite); + auto storageImage = reinterpret_cast<StorageImageDescriptor *>(memToWrite); for(uint32_t i = 0; i < entry.descriptorCount; i++) { - auto update = reinterpret_cast<VkDescriptorImageInfo const *>(src + entry.offset + entry.stride * i); - auto imageView = vk::Cast(update->imageView); - descriptor[i].ptr = imageView->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0); - descriptor[i].extent = imageView->getMipLevelExtent(0); - descriptor[i].rowPitchBytes = imageView->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0); - descriptor[i].samplePitchBytes = 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; - descriptor[i].sampleCount = imageView->getSampleCount(); - descriptor[i].sizeInBytes = static_cast<int>(imageView->getSizeInBytes()); - descriptor[i].memoryOwner = imageView; + auto *update = reinterpret_cast<VkDescriptorImageInfo const *>(src + entry.offset + entry.stride * i); + auto *imageView = vk::Cast(update->imageView); + const auto &extent = imageView->getMipLevelExtent(0); + auto layerCount = imageView->getSubresourceRange().layerCount; + + storageImage[i].ptr = imageView->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0); + storageImage[i].width = extent.width; + storageImage[i].height = extent.height; + storageImage[i].depth = imageView->getDepthOrLayerCount(0); + storageImage[i].rowPitchBytes = imageView->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0); + storageImage[i].samplePitchBytes = imageView->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0); + storageImage[i].slicePitchBytes = layerCount > 1 + ? imageView->layerPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT) + : imageView->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0); + storageImage[i].sampleCount = imageView->getSampleCount(); + storageImage[i].sizeInBytes = static_cast<int>(imageView->getSizeInBytes()); + storageImage[i].memoryOwner = imageView; if(imageView->getFormat().isStencil()) { - descriptor[i].stencilPtr = imageView->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0); - descriptor[i].stencilRowPitchBytes = imageView->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0); - descriptor[i].stencilSamplePitchBytes = imageView->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0); - descriptor[i].stencilSlicePitchBytes = (imageView->getSubresourceRange().layerCount > 1) - ? imageView->layerPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT) - : imageView->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0); + storageImage[i].stencilPtr = imageView->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0); + storageImage[i].stencilRowPitchBytes = imageView->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0); + storageImage[i].stencilSamplePitchBytes = imageView->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0); + storageImage[i].stencilSlicePitchBytes = (imageView->getSubresourceRange().layerCount > 1) + ? imageView->layerPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT) + : imageView->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0); } } } else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { - auto descriptor = reinterpret_cast<StorageImageDescriptor *>(memToWrite); + auto *storageImage = reinterpret_cast<StorageImageDescriptor *>(memToWrite); for(uint32_t i = 0; i < entry.descriptorCount; i++) { auto update = reinterpret_cast<VkBufferView const *>(src + entry.offset + entry.stride * i); auto bufferView = vk::Cast(*update); - descriptor[i].ptr = bufferView->getPointer(); - descriptor[i].extent = { bufferView->getElementCount(), 1, 1 }; - descriptor[i].rowPitchBytes = 0; - descriptor[i].slicePitchBytes = 0; - descriptor[i].samplePitchBytes = 0; - descriptor[i].arrayLayers = 1; - descriptor[i].sampleCount = 1; - descriptor[i].sizeInBytes = bufferView->getRangeInBytes(); + storageImage[i].ptr = bufferView->getPointer(); + storageImage[i].width = bufferView->getElementCount(); + storageImage[i].height = 1; + storageImage[i].depth = 1; + storageImage[i].rowPitchBytes = 0; + storageImage[i].slicePitchBytes = 0; + storageImage[i].samplePitchBytes = 0; + storageImage[i].sampleCount = 1; + storageImage[i].sizeInBytes = bufferView->getRangeInBytes(); } } else if(entry.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || @@ -477,14 +485,14 @@ entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) { - auto descriptor = reinterpret_cast<BufferDescriptor *>(memToWrite); + auto *bufferDescriptor = reinterpret_cast<BufferDescriptor *>(memToWrite); for(uint32_t i = 0; i < entry.descriptorCount; i++) { auto update = reinterpret_cast<VkDescriptorBufferInfo const *>(src + entry.offset + entry.stride * i); auto buffer = vk::Cast(update->buffer); - descriptor[i].ptr = buffer->getOffsetPointer(update->offset); - descriptor[i].sizeInBytes = static_cast<int>((update->range == VK_WHOLE_SIZE) ? buffer->getSize() - update->offset : update->range); - descriptor[i].robustnessSize = static_cast<int>(buffer->getSize() - update->offset); + bufferDescriptor[i].ptr = buffer->getOffsetPointer(update->offset); + bufferDescriptor[i].sizeInBytes = static_cast<int>((update->range == VK_WHOLE_SIZE) ? buffer->getSize() - update->offset : update->range); + bufferDescriptor[i].robustnessSize = static_cast<int>(buffer->getSize() - update->offset); } } }
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp index 6c7e159..f1919b1 100644 --- a/src/Vulkan/VkDescriptorSetLayout.hpp +++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -44,8 +44,9 @@ VkFormat format; VkComponentMapping swizzle; alignas(16) sw::Texture texture; - VkExtent3D extent; // Of base mip-level. - int arrayLayers; + int width; // Of base mip-level. + int height; + int depth; // Layer/cube count for arrayed images int mipLevels; int sampleCount; @@ -57,11 +58,12 @@ ~StorageImageDescriptor() = delete; void *ptr; - VkExtent3D extent; + int width; + int height; + int depth; // Layer/cube count for arrayed images int rowPitchBytes; int slicePitchBytes; // Layer pitch in case of array image int samplePitchBytes; - int arrayLayers; int sampleCount; int sizeInBytes;
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp index e8a6cad..421a37f 100644 --- a/src/Vulkan/VkImageView.cpp +++ b/src/Vulkan/VkImageView.cpp
@@ -13,6 +13,7 @@ // limitations under the License. #include "VkImageView.hpp" + #include "VkImage.hpp" #include "System/Math.hpp" @@ -286,6 +287,22 @@ subresourceRange.baseMipLevel + mipLevel); } +int ImageView::getDepthOrLayerCount(uint32_t mipLevel) const +{ + VkExtent3D extent = getMipLevelExtent(mipLevel); + int layers = subresourceRange.layerCount; + int depthOrLayers = layers > 1 ? layers : extent.depth; + + // For cube images the number of whole cubes is returned + if(viewType == VK_IMAGE_VIEW_TYPE_CUBE || + viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) + { + depthOrLayers /= 6; + } + + return depthOrLayers; +} + void *ImageView::getOffsetPointer(const VkOffset3D &offset, VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer, Usage usage) const { ASSERT(mipLevel < subresourceRange.levelCount);
diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp index 297ffd1..eb377ab 100644 --- a/src/Vulkan/VkImageView.hpp +++ b/src/Vulkan/VkImageView.hpp
@@ -88,6 +88,7 @@ int getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel, Usage usage = RAW) const; int layerPitchBytes(VkImageAspectFlagBits aspect, Usage usage = RAW) const; VkExtent3D getMipLevelExtent(uint32_t mipLevel) const; + int getDepthOrLayerCount(uint32_t mipLevel) const; int getSampleCount() const {