Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions tools/clang/include/clang/SPIRV/SpirvContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <array>
#include <limits>
#include <optional>

#include "dxc/DXIL/DxilShaderModel.h"
#include "clang/AST/DeclTemplate.h"
Expand Down Expand Up @@ -138,7 +139,7 @@ struct FunctionTypeMapInfo {
struct VkImageFeatures {
// True if it is a Vulkan "Combined Image Sampler".
bool isCombinedImageSampler;
spv::ImageFormat format; // SPIR-V image format.
std::optional<spv::ImageFormat> format; // SPIR-V image format.
};

// A struct that contains the information of a resource that will be used to
Expand Down Expand Up @@ -378,7 +379,7 @@ class SpirvContext {
getVkImageFeaturesForSpirvVariable(const SpirvVariable *spvVar) {
auto itr = spvVarToVkImageFeatures.find(spvVar);
if (itr == spvVarToVkImageFeatures.end())
return {false, spv::ImageFormat::Unknown};
return {false, std::nullopt};
return itr->second;
}

Expand Down
25 changes: 2 additions & 23 deletions tools/clang/lib/SPIRV/CapabilityVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,36 +439,13 @@ bool CapabilityVisitor::visit(SpirvImageSparseTexelsResident *instr) {
return true;
}

namespace {
bool isImageOpOnUnknownFormat(const SpirvImageOp *instruction) {
if (!instruction->getImage() || !instruction->getImage()->getResultType()) {
return false;
}

const ImageType *imageType =
dyn_cast<ImageType>(instruction->getImage()->getResultType());
if (!imageType || imageType->getImageFormat() != spv::ImageFormat::Unknown) {
return false;
}

return imageType->getImageFormat() == spv::ImageFormat::Unknown;
}
} // namespace

bool CapabilityVisitor::visit(SpirvImageOp *instr) {
addCapabilityForType(instr->getResultType(), instr->getSourceLocation(),
instr->getStorageClass());
if (instr->hasOffset() || instr->hasConstOffsets())
addCapability(spv::Capability::ImageGatherExtended);
if (instr->isSparse())
addCapability(spv::Capability::SparseResidency);

if (isImageOpOnUnknownFormat(instr)) {
addCapability(instr->isImageWrite()
? spv::Capability::StorageImageWriteWithoutFormat
: spv::Capability::StorageImageReadWithoutFormat);
}

return true;
}

Expand Down Expand Up @@ -864,6 +841,8 @@ bool CapabilityVisitor::visit(SpirvModule *, Visitor::Phase phase) {
// supports only some capabilities. This list should be expanded to match the
// supported capabilities.
addCapability(spv::Capability::MinLod);
addCapability(spv::Capability::StorageImageWriteWithoutFormat);
addCapability(spv::Capability::StorageImageReadWithoutFormat);

addExtensionAndCapabilitiesIfEnabled(
Extension::EXT_fragment_shader_interlock,
Expand Down
15 changes: 8 additions & 7 deletions tools/clang/lib/SPIRV/DeclResultIdMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,9 +517,10 @@ SpirvLayoutRule getLayoutRuleForExternVar(QualType type,
return SpirvLayoutRule::Void;
}

spv::ImageFormat getSpvImageFormat(const VKImageFormatAttr *imageFormatAttr) {
std::optional<spv::ImageFormat>
getSpvImageFormat(const VKImageFormatAttr *imageFormatAttr) {
if (imageFormatAttr == nullptr)
return spv::ImageFormat::Unknown;
return std::nullopt;

switch (imageFormatAttr->getImageFormat()) {
case VKImageFormatAttr::unknown:
Expand Down Expand Up @@ -1235,14 +1236,13 @@ SpirvVariable *DeclResultIdMapper::createExternVar(const VarDecl *var,
VkImageFeatures vkImgFeatures = {
var->getAttr<VKCombinedImageSamplerAttr>() != nullptr,
getSpvImageFormat(var->getAttr<VKImageFormatAttr>())};
if (vkImgFeatures.format != spv::ImageFormat::Unknown) {
if (vkImgFeatures.format) {
// Legalization is needed to propagate the correct image type for
// instructions in addition to cases where the resource is assigned to
// another variable or function parameter
needsLegalization = true;
}
if (vkImgFeatures.isCombinedImageSampler ||
vkImgFeatures.format != spv::ImageFormat::Unknown) {
if (vkImgFeatures.isCombinedImageSampler || vkImgFeatures.format) {
spvContext.registerVkImageFeaturesForSpvVariable(varInstr, vkImgFeatures);
}

Expand All @@ -1256,8 +1256,9 @@ SpirvVariable *DeclResultIdMapper::createExternVar(const VarDecl *var,
}

if (hlsl::IsHLSLResourceType(type)) {
if (!areFormatAndTypeCompatible(vkImgFeatures.format,
hlsl::GetHLSLResourceResultType(type))) {
if (!areFormatAndTypeCompatible(
vkImgFeatures.format.value_or(spv::ImageFormat::Unknown),
hlsl::GetHLSLResourceResultType(type))) {
emitError("The image format and the sampled type are not compatible.\n"
"For the table of compatible types, see "
"https://docs.vulkan.org/spec/latest/appendices/"
Expand Down
10 changes: 6 additions & 4 deletions tools/clang/lib/SPIRV/LowerTypeVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,17 @@ bool LowerTypeVisitor::visitInstruction(SpirvInstruction *instr) {
}

auto vkImgFeatures = spvContext.getVkImageFeaturesForSpirvVariable(var);
if (vkImgFeatures.format != spv::ImageFormat::Unknown) {
if (vkImgFeatures.format) {
if (const auto *imageType = dyn_cast<ImageType>(resultType)) {
resultType = spvContext.getImageType(imageType, vkImgFeatures.format);
resultType =
spvContext.getImageType(imageType, *vkImgFeatures.format);
instr->setResultType(resultType);
} else if (const auto *arrayType = dyn_cast<ArrayType>(resultType)) {
if (const auto *imageType =
dyn_cast<ImageType>(arrayType->getElementType())) {
auto newImgType =
spvContext.getImageType(imageType, vkImgFeatures.format);
auto newImgType = spvContext.getImageType(
imageType,
vkImgFeatures.format.value_or(spv::ImageFormat::Unknown));
resultType = spvContext.getArrayType(newImgType,
arrayType->getElementCount(),
arrayType->getStride());
Expand Down
3 changes: 1 addition & 2 deletions tools/clang/test/CodeGenSPIRV/op.buffer.access.hlsl
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv | FileCheck %s

// CHECK: OpCapability ImageBuffer
// CHECK: OpCapability StorageImageReadWithoutFormat

// CHECK-NOT: OpCapability StorageImageReadWithoutFormat

// CHECK: %type_buffer_image = OpTypeImage %int Buffer 2 0 0 1 R32i
// CHECK: %type_buffer_image_0 = OpTypeImage %uint Buffer 2 0 0 1 R32ui
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %dxc -T cs_6_7 -E main -spirv -fspv-target-env=vulkan1.3 %s

// CHECK: OpCapability StorageImageWriteWithoutFormat

// CHECK: %[[#image:]] = OpTypeImage %float 3D 2 0 0 2 Unknown
[[vk::image_format("unknown")]] RWTexture3D<float32_t2> untypedImage;

[numthreads(8,8,8)]
void main(uint32_t3 gl_GlobalInvocationID : SV_DispatchThreadID)
{
// CHECK: %[[#tmp:]] = OpLoad %[[#image]] %[[#]]
// CHECK: OpImageWrite [[#tmp]] %[[#]] %[[#]] None
untypedImage[gl_GlobalInvocationID] = float32_t2(4,5);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %dxc -T cs_6_7 -E main -spirv -fspv-target-env=vulkan1.3 %s

// CHECK: OpCapability StorageImageReadWithoutFormat

// CHECK: %[[#image:]] = OpTypeImage %float 1D 2 0 0 2 Unknown
[[vk::image_format("unknown")]] RWTexture1D<float32_t2> untypedImage;
RWStructuredBuffer<float32_t2> output;

[numthreads(8,8,8)]
void main()
{
// CHECK: %[[#tmp:]] = OpLoad %[[#image]] %[[#]]
// CHECK: OpImageRead %[[#]] [[#tmp]] %[[#]] None
output[0] = untypedImage[0];
}