summaryrefslogtreecommitdiff
path: root/source/slang/slang-emit-spirv.cpp
diff options
context:
space:
mode:
authorArielG-NV <159081215+ArielG-NV@users.noreply.github.com>2024-04-03 09:30:46 -0400
committerGitHub <noreply@github.com>2024-04-03 09:30:46 -0400
commita697b2c6707ee699cb734a03fa529dd214ac66cc (patch)
tree1b68f4267159828092b512361faff4729510ea39 /source/slang/slang-emit-spirv.cpp
parentc0482ec12d683e53aca56543b620a4ec02082e29 (diff)
Implement 8.14-8.19 of OpenGL-GLSL specification
The following PR implements 8.14-8.19 of the [OpenGL-GLSL specification](https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf). Fully implements all functions and built-in type's, resolves https://github.com/shader-slang/slang/issues/3692 for GLSL & SPRI-V targets. _Notes:_ Testing Tools: * Fragment shaders cannot test computational results. Only OpCodes are checked for proper emitting. Implementation Notes: * SubpassInput requires an unknown image format. * SubpassInput is disjoint from TextureType: __SubpassImpl (.slang) & SubpassInputType (Compiler) to reduce code generation required. * SubpassInput required an additional input layout modifier, input_attachment_index, this was added as a new parameter binding attribute. Since the following qualifiers can overlap with different resources (`layout(input_attachment_index = 0, binding = 0, set = 0)`) input_attachment_index is checked for overlapping resource bindings separately from other qualifiers with `LayoutResourceKind::InputAttachmentIndex`. * `GLSLInputAttachmentIndexLayoutModifier` was added to enforce function parameters only accepting `in` decorated variables. * `in` decorated variables needed to have emitting modified to allow directly emitting the variable into function calls if used as a parameter, normally Slang has a "global variable" shadow as a "global parameter" through a copy. This does not work and is solved using `GlobalVariableShadowingGlobalParameterDecoration` to build a relationship of "global variable" to "global parameter", we then resolve this relationship and replace "global variable" uses later in compile. * `AtomicCounterMemory` memory-constraint requires `OpCapability AtomicStorage`, `AtomicStorage` is invalid for Vulkan targets. glslang outputs for `barrier`, `memoryBarrier`, and `groupMemoryBarrier` `AtomicCounterMemory` as a memory constraint. This compiles as valid SPIR-V for Vulkan since `OpCapability AtomicStorage` is not declared. This behavior of glslang is undefined as per [3.31.Capability of the SPIR-V specification](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_capability). We will omit `AtomicCounterMemory` from our barrier calls.
Diffstat (limited to 'source/slang/slang-emit-spirv.cpp')
-rw-r--r--source/slang/slang-emit-spirv.cpp127
1 files changed, 80 insertions, 47 deletions
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index d32530b90..91078e1fa 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -1514,6 +1514,8 @@ struct SPIRVEmitContext
SpvLiteralInteger::from32(stride));
return arrayType;
}
+ case kIROp_SubpassInputType:
+ return ensureSubpassInputType(inst, cast<IRSubpassInputType>(inst));
case kIROp_TextureType:
return ensureTextureType(inst, cast<IRTextureType>(inst));
case kIROp_SamplerStateType:
@@ -1824,39 +1826,62 @@ struct SPIRVEmitContext
}
}
- SpvInst* ensureTextureType(IRInst* assignee, IRTextureTypeBase* inst)
+ struct ImageOpConstants
{
- // Some untyped constants from OpTypeImage
- // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage
-
- // indicates not a depth image
- [[maybe_unused]]
- const SpvWord notDepthImage = 0;
- // indicates a depth image
- [[maybe_unused]]
- const SpvWord isDepthImage = 1;
- // means no indication as to whether this is a depth or non-depth image
- const SpvWord unknownDepthImage = 2;
-
- // indicates non-arrayed content
- const SpvWord notArrayed = 0;
- // indicates arrayed content
- const SpvWord isArrayed = 1;
-
- // indicates single-sampled content
- const SpvWord notMultisampled = 0;
- // indicates multisampled content
- const SpvWord isMultisampled = 1;
-
- // indicates this is only known at run time, not at compile time
- const SpvWord sampledUnknown = 0;
- // indicates an image compatible with sampling operations
- const SpvWord sampledImage = 1;
- // indicates an image compatible with read/write operations (a storage or subpass data image).
- const SpvWord readWriteImage = 2;
+ enum : SpvWord
+ {
+ // Some untyped constants from OpTypeImage
+ // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage
- //
+ // indicates not a depth image
+ notDepthImage = 0,
+ // indicates a depth image
+ isDepthImage = 1,
+ // means no indication as to whether this is a depth or non-depth image
+ unknownDepthImage = 2,
+
+ // indicates non-arrayed content
+ notArrayed = 0,
+ // indicates arrayed content
+ isArrayed = 1,
+
+ // indicates this is only known at run time, not at compile time
+ sampledUnknown = 0,
+ // indicates an image compatible with sampling operations
+ sampledImage = 1,
+ // indicates an image compatible with read/write operations (a storage or subpass data image).
+ readWriteImage = 2,
+
+ // indicates single-sampled content
+ notMultisampled = 0,
+ // indicates multisampled content
+ isMultisampled = 1,
+ };
+ };
+
+ SpvInst* ensureSubpassInputType(IRInst* assignee, IRSubpassInputType* inst)
+ {
+ IRInst* sampledType = inst->getElementType();
+ SpvDim dim = SpvDimSubpassData;
+ SpvWord ms = inst->isMultisample() ? ImageOpConstants::isMultisampled : ImageOpConstants::notMultisampled;
+ SpvWord sampled = 2;
+ requireSPIRVCapability(SpvCapabilityInputAttachment);
+ requireSPIRVCapability(SpvCapabilityStorageImageReadWithoutFormat);
+ setImageFormatCapabilityAndExtension(SpvImageFormatUnknown, SpvCapabilityShader);
+ return emitOpTypeImage(
+ assignee,
+ dropVector((IRType*)sampledType),
+ dim,
+ SpvLiteralInteger::from32(ImageOpConstants::unknownDepthImage),
+ SpvLiteralInteger::from32(0),
+ SpvLiteralInteger::from32(ms),
+ SpvLiteralInteger::from32(sampled),
+ SpvImageFormatUnknown
+ );
+ }
+ SpvInst* ensureTextureType(IRInst* assignee, IRTextureTypeBase* inst)
+ {
IRInst* sampledType = inst->getElementType();
SpvDim dim = SpvDim1D; // Silence uninitialized warnings from msvc...
switch(inst->GetBaseShape())
@@ -1877,22 +1902,22 @@ struct SPIRVEmitContext
dim = SpvDimBuffer;
break;
}
- SpvWord arrayed = inst->isArray() ? isArrayed : notArrayed;
+ SpvWord arrayed = inst->isArray() ? ImageOpConstants::isArrayed : ImageOpConstants::notArrayed;
// Vulkan spec 16.1: "The “Depth” operand of OpTypeImage is ignored."
- SpvWord depth = unknownDepthImage; // No knowledge of if this is a depth image
- SpvWord ms = inst->isMultisample() ? isMultisampled : notMultisampled;
+ SpvWord depth = ImageOpConstants::unknownDepthImage; // No knowledge of if this is a depth image
+ SpvWord ms = inst->isMultisample() ? ImageOpConstants::isMultisampled : ImageOpConstants::notMultisampled;
- SpvWord sampled = sampledUnknown;
+ SpvWord sampled = ImageOpConstants::sampledUnknown;
switch(inst->getAccess())
{
case SlangResourceAccess::SLANG_RESOURCE_ACCESS_READ_WRITE:
case SlangResourceAccess::SLANG_RESOURCE_ACCESS_RASTER_ORDERED:
- sampled = readWriteImage;
+ sampled = ImageOpConstants::readWriteImage;
break;
case SlangResourceAccess::SLANG_RESOURCE_ACCESS_NONE:
case SlangResourceAccess::SLANG_RESOURCE_ACCESS_READ:
- sampled = sampledImage;
+ sampled = ImageOpConstants::sampledImage;
break;
}
@@ -1953,40 +1978,37 @@ struct SPIRVEmitContext
// Capabilities, according to section 3.8
//
// SPIR-V requires that the sampled/rw info on the image isn't unknown
- SLANG_ASSERT(sampled == sampledImage || sampled == readWriteImage);
- if(isMultisampled)
+ SLANG_ASSERT(sampled == ImageOpConstants::sampledImage || sampled == ImageOpConstants::readWriteImage);
+ if(ms == ImageOpConstants::isMultisampled)
requireSPIRVCapability(SpvCapabilityStorageImageMultisample);
switch(dim)
{
case SpvDim1D:
- requireSPIRVCapability(sampled == sampledImage ? SpvCapabilitySampled1D : SpvCapabilityImage1D);
+ requireSPIRVCapability(sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampled1D : SpvCapabilityImage1D);
break;
case SpvDim2D:
// Also requires Shader or Kernel, but these are a given (?)
- if(sampled == readWriteImage && ms == isMultisampled && arrayed == isArrayed)
+ if(sampled == ImageOpConstants::readWriteImage && ms == ImageOpConstants::isMultisampled && arrayed == ImageOpConstants::isArrayed)
requireSPIRVCapability(SpvCapabilityImageMSArray);
break;
case SpvDim3D:
break;
case SpvDimCube:
// Requires shader also
- if(sampled == readWriteImage && arrayed == isArrayed)
+ if(sampled == ImageOpConstants::readWriteImage && arrayed == ImageOpConstants::isArrayed)
requireSPIRVCapability(SpvCapabilityImageCubeArray);
break;
case SpvDimRect:
- requireSPIRVCapability(sampled == sampledImage ? SpvCapabilitySampledRect : SpvCapabilityImageRect);
+ requireSPIRVCapability(sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampledRect : SpvCapabilityImageRect);
break;
case SpvDimBuffer:
- requireSPIRVCapability(sampled == sampledImage ? SpvCapabilitySampledBuffer : SpvCapabilityImageBuffer);
- break;
- case SpvDimSubpassData:
- requireSPIRVCapability(SpvCapabilityInputAttachment);
+ requireSPIRVCapability(sampled == ImageOpConstants::sampledImage ? SpvCapabilitySampledBuffer : SpvCapabilityImageBuffer);
break;
case SpvDimTileImageDataEXT:
SLANG_UNIMPLEMENTED_X("OpTypeImage Capabilities for SpvDimTileImageDataEXT");
break;
}
- if(format == SpvImageFormatUnknown && sampled == readWriteImage)
+ if(format == SpvImageFormatUnknown && sampled == ImageOpConstants::readWriteImage)
{
// TODO: It may not be necessary to have both of these
// depending on if we read or write
@@ -3290,6 +3312,17 @@ struct SPIRVEmitContext
);
}
break;
+ case kIROp_GLSLInputAttachmentIndexDecoration:
+ {
+ const auto c = cast<IRGLSLInputAttachmentIndexDecoration>(decoration);
+ emitOpDecorateInputAttachmentIndex(
+ getSection(SpvLogicalSectionID::Annotations),
+ decoration,
+ dstID,
+ SpvLiteralInteger::from32(int32_t(c->getIndex()->getValue()))
+ );
+ }
+ break;
case kIROp_VulkanHitAttributesDecoration:
case kIROp_VulkanCallablePayloadDecoration: