summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/compiler-core/slang-dxc-compiler.cpp148
-rw-r--r--source/core/slang-char-util.h2
-rw-r--r--source/core/slang-command-line.cpp8
-rw-r--r--source/core/slang-command-line.h2
-rw-r--r--source/slang/hlsl.meta.slang203
-rw-r--r--source/slang/slang-artifact-output-util.cpp3
-rw-r--r--source/slang/slang-emit-c-like.cpp27
-rw-r--r--source/slang/slang-lower-to-ir.cpp12
8 files changed, 349 insertions, 56 deletions
diff --git a/source/compiler-core/slang-dxc-compiler.cpp b/source/compiler-core/slang-dxc-compiler.cpp
index 06dfc74b0..2856a77ab 100644
--- a/source/compiler-core/slang-dxc-compiler.cpp
+++ b/source/compiler-core/slang-dxc-compiler.cpp
@@ -181,9 +181,26 @@ protected:
DxcCreateInstanceProc m_createInstance = nullptr;
+ /// The commit hash associated with the DXC dll used
+ /// If 0 length, no hash was found
+ String m_commitHash;
+ /// The commit count. 0 if not set
+ uint32_t m_commitCount = 0;
+
ComPtr<ISlangSharedLibrary> m_sharedLibrary;
};
+static String _moveTaskMemAllocatedToString(char* chars)
+{
+ if (chars)
+ {
+ const String str(chars);
+ ::CoTaskMemFree(chars);
+ return str;
+ }
+ return String();
+}
+
SlangResult DXCDownstreamCompiler::init(ISlangSharedLibrary* library)
{
m_sharedLibrary = library;
@@ -194,7 +211,69 @@ SlangResult DXCDownstreamCompiler::init(ISlangSharedLibrary* library)
return SLANG_FAIL;
}
- m_desc = Desc(SLANG_PASS_THROUGH_DXC);
+ // Must be able to create the compiler. We inly do this here, because we want to get the compiler
+ // version.
+ ComPtr<IDxcCompiler> dxcCompiler;
+ SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcCompiler, __uuidof(dxcCompiler), (LPVOID*)dxcCompiler.writeRef()));
+
+ uint32_t major = 0;
+ uint32_t minor = 0;
+ uint32_t patch = 0;
+
+ // Get the version info
+ {
+ ComPtr<IDxcVersionInfo> versionInfo;
+ if (SLANG_SUCCEEDED(dxcCompiler->QueryInterface(versionInfo.writeRef())))
+ {
+ versionInfo->GetVersion(&major, &minor);
+ }
+ }
+
+ // Get the commit hash
+ {
+
+ ComPtr<IDxcVersionInfo2> versionInfo;
+ if (SLANG_SUCCEEDED(dxcCompiler->QueryInterface(versionInfo.writeRef())))
+ {
+ char* commitHash = nullptr;
+ versionInfo->GetCommitInfo(&m_commitCount, &commitHash);
+ m_commitHash = _moveTaskMemAllocatedToString(commitHash);
+ }
+ }
+
+ // Try and get the custom build string, as we can potentially get the patch version from that.
+ if (patch == 0)
+ {
+ ComPtr<IDxcVersionInfo3> versionInfo;
+
+ if (SLANG_SUCCEEDED(dxcCompiler->QueryInterface(versionInfo.writeRef())))
+ {
+ char* customVersionCString = nullptr;
+ versionInfo->GetCustomVersionString(&customVersionCString);
+
+ const String customVersionString = _moveTaskMemAllocatedToString(customVersionCString);
+
+ SemanticVersion semanticVersion(int(major), int(minor), 0);
+ StringBuilder buf;
+ semanticVersion.append(buf);
+
+ if (customVersionString.startsWith(buf) &&
+ customVersionString.getLength() > buf.getLength() + 2 &&
+ customVersionString[buf.getLength()] == '.')
+ {
+ // Get the patch slice
+ UnownedStringSlice patchSlice = StringUtil::getAtInSplit(customVersionString.getUnownedSlice(), '.', 2);
+
+ Int patchValue;
+ if (SLANG_SUCCEEDED(StringUtil::parseInt(patchSlice, patchValue)) && patchValue > 0)
+ {
+ patch = uint32_t(patchValue);
+ }
+ }
+ }
+ }
+
+ m_desc = Desc(SLANG_PASS_THROUGH_DXC, SemanticVersion(int(major), int(minor), int(patch)));
return SLANG_OK;
}
@@ -438,6 +517,22 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& options, IArtif
searchDirectories.searchDirectories.add(asString(includePath));
}
+ // TODO(JS): Enable in a better way perhaps?
+ {
+ // Strictly speaking the HLSL2021 was available in 1.6.2112, in preview
+ // We enable on 1.7.2207 as that is the first official version, but
+ // since we may not be able to get the patch version, we'll just assume any version
+ // over 1.7 has can support the feature.
+
+ const SemanticVersion firstHlsl2021Version(1, 7);
+
+ if (m_desc.version >= firstHlsl2021Version)
+ {
+ args.add(L"-HV");
+ args.add(L"2021");
+ }
+ }
+
String sourcePath = ArtifactUtil::findPath(sourceArtifact);
OSString wideSourcePath = sourcePath.toWString();
@@ -577,50 +672,21 @@ SlangResult DXCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc&
SlangResult DXCDownstreamCompiler::getVersionString(slang::IBlob** outVersionString)
{
- ComPtr<IDxcCompiler> dxcCompiler;
- SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcCompiler, __uuidof(dxcCompiler), (LPVOID*)dxcCompiler.writeRef()));
+ StringBuilder versionString;
+ // Append the version
+ m_desc.version.append(versionString);
- ComPtr<ISlangBlob> version;
- ComPtr<IDxcVersionInfo> versionInfo;
- if (SLANG_SUCCEEDED(dxcCompiler->QueryInterface(versionInfo.writeRef())))
+ if (m_commitHash.getLength())
+ {
+ versionString << "#" << m_commitHash;
+ }
+ else
{
- // Because the major/minor version alone does not necessarily capture different releases
- // of the DX compiler, we also need to query for the commit hash. If we are unable to
- // obtain the commit hash, then we return the shared library timestamp instead.
- ComPtr<IDxcVersionInfo2> versionInfo2;
- if (SLANG_SUCCEEDED(dxcCompiler->QueryInterface(versionInfo2.writeRef())))
- {
- uint32_t major;
- uint32_t minor;
- versionInfo->GetVersion(&major, &minor);
-
- StringBuilder versionString;
- versionString.append(major);
- versionString.append(".");
- versionString.append(minor);
-
- char* commitHash = nullptr;
- uint32_t unused;
- versionInfo2->GetCommitInfo(&unused, &commitHash);
- if (commitHash)
- {
- // Successfully queried the commit hash, append to the version and return.
- versionString.append(commitHash);
- CoTaskMemFree(commitHash);
-
- version = StringBlob::create(versionString.getBuffer());
- *outVersionString = version.detach();
- return SLANG_OK;
- }
- }
+ // If we don't have the commitHash, we use the library timestamp, to uniquely identify.
+ versionString << " " << SharedLibraryUtils::getSharedLibraryTimestamp(m_createInstance);
}
- // If either of the QueryInterface calls fails, we return the shared library timestamp
- // as the version instead.
- auto timestamp = SharedLibraryUtils::getSharedLibraryTimestamp(m_createInstance);
- auto timestampString = String(timestamp);
- version = StringBlob::create(timestampString.getBuffer());
- *outVersionString = version.detach();
+ *outVersionString = StringBlob::moveCreate(versionString).detach();
return SLANG_OK;
}
diff --git a/source/core/slang-char-util.h b/source/core/slang-char-util.h
index f831f6d55..40abee602 100644
--- a/source/core/slang-char-util.h
+++ b/source/core/slang-char-util.h
@@ -30,6 +30,8 @@ struct CharUtil
/// True if it's alpha
SLANG_FORCE_INLINE static bool isAlpha(char c) { return (getFlags(c) & (Flag::Upper | Flag::Lower)) != 0; }
+ /// True if it's alpha or a digit
+ SLANG_FORCE_INLINE static bool isAlphaOrDigit(char c) { return (getFlags(c) & (Flag::Upper | Flag::Lower | Flag::Digit)) != 0; }
/// True if the character is a valid hex character
SLANG_FORCE_INLINE static bool isHexDigit(char c) { return (getFlags(c) & Flag::HexDigit) != 0; }
diff --git a/source/core/slang-command-line.cpp b/source/core/slang-command-line.cpp
index f8b5ff10f..59e6a6265 100644
--- a/source/core/slang-command-line.cpp
+++ b/source/core/slang-command-line.cpp
@@ -116,6 +116,14 @@ void CommandLine::appendArgs(StringBuilder& out) const
}
}
+void CommandLine::addArgIfNotFound(const String& in)
+{
+ if (m_args.indexOf(in) < 0)
+ {
+ addArg(in);
+ }
+}
+
String CommandLine::toString() const
{
StringBuilder buf;
diff --git a/source/core/slang-command-line.h b/source/core/slang-command-line.h
index f2007865f..163daf710 100644
--- a/source/core/slang-command-line.h
+++ b/source/core/slang-command-line.h
@@ -62,6 +62,8 @@ struct CommandLine
void addArg(const String& in) { m_args.add(in); }
void addArgs(const String* args, Int argsCount) { for (Int i = 0; i < argsCount; ++i) addArg(args[i]); }
+ void addArgIfNotFound(const String& in);
+
/// Find the index of an arg which is exact match for slice
SLANG_INLINE Index findArgIndex(const UnownedStringSlice& slice) const { return m_args.indexOf(slice); }
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index fe3d511d4..238739fcd 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -5420,3 +5420,206 @@ struct VkSubpassInputMS<T>
{
T SubpassLoad(int sampleIndex);
}
+
+///
+/// Shader Execution Reordering (SER)
+///
+/// NOTE! This API is currently experimental and may change in the future as SER is made available
+/// in different APIs and downstream compilers.
+///
+/// Based on the NVAPI on D3D12 only currently.
+///
+/// White paper on SER on NVAPI https://developer.nvidia.com/sites/default/files/akamai/gameworks/ser-whitepaper.pdf
+///
+/// The NVAPI headers (R520) required for this functionality to work can be found here...
+///
+/// https://developer.nvidia.com/rtx/path-tracing/nvapi/get-started
+///
+
+ /// Immutable data type representing a ray hit or a miss. Can be used to invoke hit or miss shading,
+ /// or as a key in ReorderThread. Created by one of several methods described below. HitObject
+ /// and its related functions are available in raytracing shader types only.
+__target_intrinsic(hlsl, NvHitObject)
+[__requiresNVAPI]
+struct HitObject
+{
+ /// Executes ray traversal (including anyhit and intersection shaders) like TraceRay, but returns the
+ /// resulting hit information as a HitObject and does not trigger closesthit or miss shaders.
+ __target_intrinsic(hlsl, "NvTraceRayHitObject")
+ [__requiresNVAPI]
+ static HitObject TraceRay<payload_t>(
+ RaytracingAccelerationStructure AccelerationStructure,
+ uint RayFlags,
+ uint InstanceInclusionMask,
+ uint RayContributionToHitGroupIndex,
+ uint MultiplierForGeometryContributionToHitGroupIndex,
+ uint MissShaderIndex,
+ RayDesc Ray,
+ inout payload_t Payload);
+
+ /// Creates a HitObject representing a hit based on values explicitly passed as arguments, without
+ /// tracing a ray. The primitive specified by AccelerationStructure, InstanceIndex, GeometryIndex,
+ /// and PrimitiveIndex must exist. The shader table index is computed using the formula used with
+ /// TraceRay. The computed index must reference a valid hit group record in the shader table. The
+ /// Attributes parameter must either be an attribute struct, such as
+ /// BuiltInTriangleIntersectionAttributes, or another HitObject to copy the attributes from.
+ __target_intrinsic(hlsl, "NvMakeHit")
+ [__requiresNVAPI]
+ static HitObject MakeHit<attr_t>(
+ RaytracingAccelerationStructure AccelerationStructure,
+ uint InstanceIndex,
+ uint GeometryIndex,
+ uint PrimitiveIndex,
+ uint HitKind,
+ uint RayContributionToHitGroupIndex,
+ uint MultiplierForGeometryContributionToHitGroupIndex,
+ RayDesc Ray,
+ attr_t attributes);
+
+ /// Creates a HitObject representing a hit based on values explicitly passed as arguments, without
+ /// tracing a ray. The primitive specified by AccelerationStructure, InstanceIndex, GeometryIndex,
+ /// and PrimitiveIndex must exist. The shader table index is explicitly provided as an argument
+ /// instead of being computed from the indexing formula used in TraceRay. The provided index must
+ /// reference a valid hit group record in the shader table. The Attributes parameter must either be an
+ /// attribute struct, such as BuiltInTriangleIntersectionAttributes, or another HitObject to copy the
+ /// attributes from.
+ __target_intrinsic(hlsl, "NvMakeHitWithRecordIndex")
+ [__requiresNVAPI]
+ static HitObject MakeHit<attr_t>(
+ uint HitGroupRecordIndex,
+ RaytracingAccelerationStructure AccelerationStructure,
+ uint InstanceIndex,
+ uint GeometryIndex,
+ uint PrimitiveIndex,
+ uint HitKind,
+ RayDesc Ray,
+ attr_t attributes);
+
+ /// Creates a HitObject representing a miss based on values explicitly passed as arguments, without
+ /// tracing a ray. The provided shader table index must reference a valid miss record in the shader
+ /// table.
+ __target_intrinsic(hlsl, "NvMakeMiss")
+ [__requiresNVAPI]
+ static HitObject MakeMiss(
+ uint MissShaderIndex,
+ RayDesc Ray);
+
+ /// Creates a HitObject representing “NOP” (no operation) which is neither a hit nor a miss. Invoking a
+ /// NOP hit object using HitObject::Invoke has no effect. Reordering by hit objects using
+ /// ReorderThread will group NOP hit objects together. This can be useful in some reordering
+ /// scenarios where future control flow for some threads is known to process neither a hit nor a
+ /// miss.
+ __target_intrinsic(hlsl, "NvMakeNop")
+ [__requiresNVAPI]
+ static HitObject MakeNop();
+
+ /// Invokes closesthit or miss shading for the specified hit object. In case of a NOP HitObject, no
+ /// shader is invoked.
+ __target_intrinsic(hlsl, "NvInvokeHitObject")
+ [__requiresNVAPI]
+ static void Invoke<payload_t>(
+ RaytracingAccelerationStructure AccelerationStructure,
+ HitObject HitOrMiss,
+ inout payload_t Payload);
+
+ /// Returns true if the HitObject encodes a miss, otherwise returns false.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ bool IsMiss();
+
+ /// Returns true if the HitObject encodes a hit, otherwise returns false.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ bool IsHit();
+
+ /// Returns true if the HitObject encodes a nop, otherwise returns false.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ bool IsNop();
+
+ /// Queries ray properties from HitObject. Valid if the hit object represents a hit or a miss.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ RayDesc GetRayDesc();
+
+ /// Queries shader table index from HitObject. Valid if the hit object represents a hit or a miss.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ uint GetShaderTableIndex();
+
+ /// Returns the instance index of a hit. Valid if the hit object represents a hit.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ uint GetInstanceIndex();
+
+ /// Returns the instance ID of a hit. Valid if the hit object represents a hit.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ uint GetInstanceID();
+
+ /// Returns the geometry index of a hit. Valid if the hit object represents a hit.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ uint GetGeometryIndex();
+
+ /// Returns the primitive index of a hit. Valid if the hit object represents a hit.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ uint GetPrimitiveIndex();
+
+ /// Returns the hit kind. Valid if the hit object represents a hit.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ uint GetHitKind();
+
+ /// Returns the attributes of a hit. Valid if the hit object represents a hit or a miss.
+ __target_intrinsic(hlsl, "$0.GetAttributes<$G0>()")
+ [__requiresNVAPI]
+ attr_t GetAttributes<attr_t>();
+
+ /// Loads a root constant from the local root table referenced by the hit object. Valid if the hit object
+ /// represents a hit or a miss. RootConstantOffsetInBytes must be a multiple of 4.
+ __target_intrinsic(hlsl)
+ [__requiresNVAPI]
+ uint LoadLocalRootTableConstant(uint RootConstantOffsetInBytes);
+};
+
+
+ /// Reorders threads based on a coherence hint value. NumCoherenceHintBits indicates how many of
+ /// the least significant bits of CoherenceHint should be considered during reordering (max: 16).
+ /// Applications should set this to the lowest value required to represent all possible values in
+ /// CoherenceHint. For best performance, all threads should provide the same value for
+ /// NumCoherenceHintBits.
+ /// Where possible, reordering will also attempt to retain locality in the thread’s launch indices
+ /// (DispatchRaysIndex in DXR).
+__target_intrinsic(hlsl, "NvReorderThread")
+[__requiresNVAPI]
+void ReorderThread( uint CoherenceHint, uint NumCoherenceHintBitsFromLSB );
+
+ /// Reorders threads based on a hit object, optionally extended by a coherence hint value. Coherence
+ /// hints behave as described in the generic variant of ReorderThread. The maximum number of
+ /// coherence hint bits in this variant of ReorderThread is 8. If no coherence hint is desired, set
+ /// NumCoherenceHitBits to zero.
+ /// Reordering will consider information in the HitObject and coherence hint with the following
+ /// priority:
+ ///
+ /// 1. Shader ID stored in the HitObject
+ /// 2. Coherence hint, with the most significant hint bit having highest priority
+ /// 3. Spatial information stored in the HitObject
+ ///
+ /// That is, ReorderThread will first attempt to group threads whose HitObject references the
+ /// same shader ID. (Miss shaders and NOP HitObjects are grouped separately). Within each of these
+ /// groups, it will attempt to order threads by the value of their coherence hints. And within ranges
+ /// of equal coherence hints, it will attempt to maximize locality in 3D space of the ray hit (if any).
+__target_intrinsic(hlsl, "NvReorderThread")
+[__requiresNVAPI]
+void ReorderThread( HitObject HitOrMiss, uint CoherenceHint, uint NumCoherenceHintBitsFromLSB );
+
+ /// Is equivalent to
+ /// ```
+ /// void ReorderThread( HitObject HitOrMiss, uint CoherenceHint, uint NumCoherenceHintBitsFromLSB );
+ /// ```
+ /// With CoherenceHint and NumCoherenceHintBitsFromLSB as 0, meaning they are ignored.
+[__requiresNVAPI]
+__target_intrinsic(hlsl, "NvReorderThread")
+void ReorderThread( HitObject HitOrMiss );
diff --git a/source/slang/slang-artifact-output-util.cpp b/source/slang/slang-artifact-output-util.cpp
index ac4138020..e9cfe6615 100644
--- a/source/slang/slang-artifact-output-util.cpp
+++ b/source/slang/slang-artifact-output-util.cpp
@@ -99,7 +99,8 @@ SlangResult ArtifactOutputUtil::maybeDisassemble(Session* session, IArtifact* ar
// If is text, we can just output
if (ArtifactDescUtil::isText(desc))
{
- return writer->write((const char*)blob->getBufferPointer(), blob->getBufferSize());
+ auto text = StringUtil::getSlice(blob);
+ return writer->write(text.begin(), text.getLength());
}
else
{
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index dcd25419e..09a18a31c 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -1472,20 +1472,31 @@ IRTargetIntrinsicDecoration* CLikeSourceEmitter::findBestTargetIntrinsicDecorati
/* static */bool CLikeSourceEmitter::isOrdinaryName(UnownedStringSlice const& name)
{
char const* cursor = name.begin();
- char const* end = name.end();
+ char const*const end = name.end();
// Consume an optional `.` at the start, which indicates
// the ordinary name is for a member function.
- if(cursor != end && *cursor == '.')
+ if(cursor < end && *cursor == '.')
cursor++;
- while(cursor != end)
+ // Must have at least one char, and first char can't be a digit
+ if (cursor >= end || CharUtil::isDigit(cursor[0]))
+ return false;
+
+ for(; cursor < end; ++cursor)
{
- int c = *cursor++;
- if( (c >= 'a') && (c <= 'z') ) continue;
- if( (c >= 'A') && (c <= 'Z') ) continue;
- if( (c >= '0') && (c <= '9') ) continue;
- if( c == '_' ) continue;
+ const auto c = *cursor;
+ if (CharUtil::isAlphaOrDigit(c) || c == '_')
+ {
+ continue;
+ }
+
+ // We allow :: for scope
+ if (c == ':' && cursor + 1 < end && cursor[1] == ':')
+ {
+ ++cursor;
+ continue;
+ }
return false;
}
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 8f00253f5..e2b14f1e3 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -7641,15 +7641,15 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// Constructors aren't really member functions, insofar
// as they aren't called with a `this` parameter.
- //
- // TODO: We may also want to exclude `static` functions
- // here for the same reason, but this routine is only
- // used for the stdlib, where we don't currently have
- // any `static` member functions to worry about.
- //
if(as<ConstructorDecl>(decl))
return false;
+ // Exclude `static` functions for same reason.
+ if (decl->findModifier<HLSLStaticModifier>())
+ {
+ return false;
+ }
+
auto dd = decl->parentDecl;
for(;;)
{